| 1 | #!/usr/bin/env bash |
| 2 | # |
| 3 | # Job control constructs: |
| 4 | # & terminator (instead of ;) |
| 5 | # $! -- last PID |
| 6 | # wait builtin (wait -n waits for next) |
| 7 | # |
| 8 | # Only interactive: |
| 9 | # fg |
| 10 | # bg |
| 11 | # %1 -- current job |
| 12 | |
| 13 | #### wait with nothing to wait for |
| 14 | wait |
| 15 | ## status: 0 |
| 16 | |
| 17 | #### wait -n with nothing to wait for |
| 18 | # The 127 is STILL overloaded. Copying bash for now. |
| 19 | wait -n |
| 20 | ## status: 127 |
| 21 | ## OK dash status: 2 |
| 22 | ## OK mksh status: 1 |
| 23 | |
| 24 | #### wait with jobspec syntax %nonexistent |
| 25 | wait %nonexistent |
| 26 | ## status: 127 |
| 27 | ## OK dash status: 2 |
| 28 | |
| 29 | #### wait with invalid PID |
| 30 | wait 12345678 |
| 31 | ## status: 127 |
| 32 | |
| 33 | #### wait with invalid arg |
| 34 | wait zzz |
| 35 | ## status: 2 |
| 36 | ## OK bash status: 1 |
| 37 | # mksh confuses a syntax error with 'command not found'! |
| 38 | ## BUG mksh status: 127 |
| 39 | |
| 40 | #### Builtin in background |
| 41 | echo async & |
| 42 | wait |
| 43 | ## stdout: async |
| 44 | |
| 45 | #### External command in background |
| 46 | sleep 0.01 & |
| 47 | wait |
| 48 | ## stdout-json: "" |
| 49 | |
| 50 | #### Pipeline in Background |
| 51 | echo hi | { exit 99; } & |
| 52 | wait $! |
| 53 | echo status=$? |
| 54 | ## stdout: status=99 |
| 55 | |
| 56 | #### Wait for job doesn't support PIPESTATUS |
| 57 | |
| 58 | # foreground works |
| 59 | { echo hi; exit 55; } | { exit 99; } |
| 60 | echo pipestatus=${PIPESTATUS[@]} |
| 61 | |
| 62 | # background doesn't work |
| 63 | { echo hi; exit 55; } | { exit 99; } & |
| 64 | wait %+ |
| 65 | echo pipestatus=${PIPESTATUS[@]} |
| 66 | ## STDOUT: |
| 67 | pipestatus=55 99 |
| 68 | pipestatus=99 |
| 69 | ## |
| 70 | ## N-I dash status: 2 |
| 71 | ## N-I dash stdout-json: "" |
| 72 | |
| 73 | #### Brace group in background, wait all |
| 74 | { sleep 0.09; exit 9; } & |
| 75 | { sleep 0.07; exit 7; } & |
| 76 | wait # wait for all gives 0 |
| 77 | echo "status=$?" |
| 78 | ## stdout: status=0 |
| 79 | |
| 80 | #### Wait on background process PID |
| 81 | { sleep 0.09; exit 9; } & |
| 82 | pid1=$! |
| 83 | { sleep 0.07; exit 7; } & |
| 84 | pid2=$! |
| 85 | wait $pid1 |
| 86 | echo "status=$?" |
| 87 | wait $pid2 |
| 88 | echo "status=$?" |
| 89 | ## stdout-json: "status=9\nstatus=7\n" |
| 90 | |
| 91 | #### Wait on multiple specific IDs returns last status |
| 92 | { sleep 0.08; exit 8; } & |
| 93 | jid1=$! |
| 94 | { sleep 0.09; exit 9; } & |
| 95 | jid2=$! |
| 96 | { sleep 0.07; exit 7; } & |
| 97 | jid3=$! |
| 98 | wait $jid1 $jid2 $jid3 # NOTE: not using %1 %2 %3 syntax on purpose |
| 99 | echo "status=$?" # third job I think |
| 100 | ## stdout: status=7 |
| 101 | |
| 102 | #### wait -n |
| 103 | { sleep 0.09; exit 9; } & |
| 104 | { sleep 0.03; exit 3; } & |
| 105 | wait -n |
| 106 | echo "status=$?" |
| 107 | wait -n |
| 108 | echo "status=$?" |
| 109 | ## stdout-json: "status=3\nstatus=9\n" |
| 110 | ## N-I dash stdout-json: "status=2\nstatus=2\n" |
| 111 | ## N-I mksh stdout-json: "status=1\nstatus=1\n" |
| 112 | |
| 113 | #### Async for loop |
| 114 | for i in 1 2 3; do |
| 115 | echo $i |
| 116 | sleep 0.0$i |
| 117 | done & |
| 118 | wait |
| 119 | ## stdout-json: "1\n2\n3\n" |
| 120 | ## status: 0 |
| 121 | |
| 122 | #### Background process doesn't affect parent |
| 123 | echo ${foo=1} |
| 124 | echo $foo |
| 125 | echo ${bar=2} & |
| 126 | wait |
| 127 | echo $bar # bar is NOT SET in the parent process |
| 128 | ## stdout-json: "1\n1\n2\n\n" |
| 129 | |
| 130 | #### Background process and then a singleton pipeline |
| 131 | |
| 132 | # This was inspired by #416, although that symptom there was timing, so it's |
| 133 | # technically not a regression test. It's hard to test timing. |
| 134 | |
| 135 | { sleep 0.1; exit 42; } & |
| 136 | echo begin |
| 137 | ! true |
| 138 | echo end |
| 139 | wait $! |
| 140 | echo status=$? |
| 141 | ## STDOUT: |
| 142 | begin |
| 143 | end |
| 144 | status=42 |
| 145 | ## END |