1 ## oils_failures_allowed: 3
2 ## oils_cpp_failures_allowed: 4
3 ## compare_shells: dash bash mksh
4
5 # Job control constructs:
6 # & terminator (instead of ;)
7 # $! -- last PID
8 # wait builtin (wait -n waits for next)
9 #
10 # Only interactive:
11 # fg
12 # bg
13 # %1 -- current job
14
15 #### wait with nothing to wait for
16 wait
17 ## status: 0
18
19 #### wait -n with arguments - arguments are respected
20 case $SH in dash|mksh) exit ;; esac
21
22 echo x &
23
24 # here, you can't tell if it's -n or the other
25 wait -n $!
26 echo status=$?
27
28 # by the bash error, you can tell which is preferred
29 wait -n $! bad 2>err.txt
30 echo status=$?
31 echo
32
33 n=$(wc -l < err.txt)
34 if test "$n" -gt 0; then
35 echo 'got error lines'
36 fi
37
38 ## STDOUT:
39 x
40 status=0
41 status=127
42
43 got error lines
44 ## END
45 ## N-I dash/mksh STDOUT:
46 ## END
47
48 #### wait -n with nothing to wait for
49 # The 127 is STILL overloaded. Copying bash for now.
50 wait -n
51 ## status: 127
52 ## N-I dash status: 2
53 ## N-I mksh status: 1
54
55 #### wait with jobspec syntax %nonexistent
56 wait %nonexistent
57 ## status: 127
58 ## OK dash status: 2
59
60 #### wait with invalid PID
61 wait 12345678
62 ## status: 127
63
64 #### wait with invalid arg
65 wait zzz
66 ## status: 2
67 ## OK bash status: 1
68 # mksh confuses a syntax error with 'command not found'!
69 ## BUG mksh status: 127
70
71 #### wait for N parallel jobs
72
73 for i in 3 2 1; do
74 { sleep 0.0$i; exit $i; } &
75 done
76 wait
77
78 # status is lost
79 echo status=$?
80
81 ## STDOUT:
82 status=0
83 ## END
84
85 #### wait for N parallel jobs and check failure
86
87 set -o errexit
88
89 pids=''
90 for i in 3 2 1; do
91 { sleep 0.0$i; echo $i; exit $i; } &
92 pids="$pids $!"
93 done
94
95 for pid in $pids; do
96 set +o errexit
97 wait $pid
98 status=$?
99 set -o errexit
100
101 echo status=$status
102 done
103
104 ## STDOUT:
105 1
106 2
107 3
108 status=3
109 status=2
110 status=1
111 ## END
112
113 #### Builtin in background
114 echo async &
115 wait
116 ## stdout: async
117
118 #### External command in background
119 sleep 0.01 &
120 wait
121 ## stdout-json: ""
122
123 #### Start background pipeline, wait $pid
124 echo hi | { exit 99; } &
125 echo status=$?
126 wait $!
127 echo status=$?
128 echo --
129
130 pids=''
131 for i in 3 2 1; do
132 sleep 0.0$i | echo i=$i | ( exit $i ) &
133 pids="$pids $!"
134 done
135 #echo "PIDS $pids"
136
137 for pid in $pids; do
138 wait $pid
139 echo status=$?
140 done
141
142 # Not cleaned up
143 if false; then
144 echo 'DEBUG'
145 jobs --debug
146 fi
147
148 ## STDOUT:
149 status=0
150 status=99
151 --
152 status=3
153 status=2
154 status=1
155 ## END
156
157 #### Start background pipeline, wait %job_spec
158 case $SH in mksh) exit ;; esac # flakiness?
159
160 echo hi | { exit 99; } &
161 echo status=$?
162 wait %1
163 echo status=$?
164 ## STDOUT:
165 status=0
166 status=99
167 ## END
168 ## BUG mksh STDOUT:
169 ## END
170
171 #### Wait for job and PIPESTATUS
172
173 # foreground
174 { echo hi; exit 55; } | false
175 echo fore status=$? pipestatus=${PIPESTATUS[@]}
176
177 # background
178 { echo hi; exit 44; } | false &
179 echo back status=$? pipestatus=${PIPESTATUS[@]}
180
181 # wait for pipeline
182 wait %+
183 #wait %1
184 #wait $!
185 echo wait status=$? pipestatus=${PIPESTATUS[@]}
186
187 ## STDOUT:
188 fore status=1 pipestatus=55 1
189 back status=0 pipestatus=0
190 wait status=1 pipestatus=1
191 ## END
192 ## N-I dash status: 2
193 ## N-I dash STDOUT:
194 ## END
195
196 #### Wait for job and PIPESTATUS - cat
197
198 # foreground
199 exit 55 | ( cat; exit 99 )
200 echo fore status=$? pipestatus=${PIPESTATUS[@]}
201
202 # background
203 exit 44 | ( cat; exit 88 ) &
204 echo back status=$? pipestatus=${PIPESTATUS[@]}
205
206 # wait for pipeline
207 wait %+
208 #wait %1
209 #wait $!
210 echo wait status=$? pipestatus=${PIPESTATUS[@]}
211 echo
212
213 # wait for non-pipeline
214 ( exit 77 ) &
215 wait %+
216 echo wait status=$? pipestatus=${PIPESTATUS[@]}
217
218 ## STDOUT:
219 fore status=99 pipestatus=55 99
220 back status=0 pipestatus=0
221 wait status=88 pipestatus=88
222
223 wait status=77 pipestatus=77
224 ## END
225 ## N-I dash status: 2
226 ## N-I dash STDOUT:
227 ## END
228
229 #### Brace group in background, wait all
230 { sleep 0.09; exit 9; } &
231 { sleep 0.07; exit 7; } &
232 wait # wait for all gives 0
233 echo "status=$?"
234 ## stdout: status=0
235
236 #### Wait on background process PID
237 { sleep 0.09; exit 9; } &
238 pid1=$!
239 { sleep 0.07; exit 7; } &
240 pid2=$!
241 wait $pid2
242 echo "status=$?"
243 wait $pid1
244 echo "status=$?"
245 ## STDOUT:
246 status=7
247 status=9
248 ## END
249
250 #### Wait on multiple specific IDs returns last status
251 { sleep 0.08; exit 8; } &
252 jid1=$!
253 { sleep 0.09; exit 9; } &
254 jid2=$!
255 { sleep 0.07; exit 7; } &
256 jid3=$!
257 wait $jid1 $jid2 $jid3 # NOTE: not using %1 %2 %3 syntax on purpose
258 echo "status=$?" # third job I think
259 ## stdout: status=7
260
261 #### wait -n
262 case $SH in dash|mksh) return ;; esac
263
264 { sleep 0.09; exit 9; } &
265 { sleep 0.03; exit 3; } &
266 wait -n
267 echo "status=$?"
268 wait -n
269 echo "status=$?"
270 ## STDOUT:
271 status=3
272 status=9
273 ## END
274 ## N-I dash/mksh stdout-json: ""
275
276 #### Async for loop
277 for i in 1 2 3; do
278 echo $i
279 sleep 0.0$i
280 done &
281 wait
282 ## STDOUT:
283 1
284 2
285 3
286 ## END
287 ## status: 0
288
289 #### Background process doesn't affect parent
290 echo ${foo=1}
291 echo $foo
292 echo ${bar=2} &
293 wait
294 echo $bar # bar is NOT SET in the parent process
295 ## STDOUT:
296 1
297 1
298 2
299
300 ## END
301
302 #### Background process and then a singleton pipeline
303
304 # This was inspired by #416, although that symptom there was timing, so it's
305 # technically not a regression test. It's hard to test timing.
306
307 { sleep 0.1; exit 42; } &
308 echo begin
309 ! true
310 echo end
311 wait $!
312 echo status=$?
313 ## STDOUT:
314 begin
315 end
316 status=42
317 ## END
318
319 #### jobs prints one line per job
320 sleep 0.1 &
321 sleep 0.1 | cat &
322
323 # dash doesn't print if it's not a terminal?
324 jobs | wc -l
325
326 ## STDOUT:
327 2
328 ## END
329 ## BUG dash STDOUT:
330 0
331 ## END
332
333 #### jobs -p prints one line per job
334 sleep 0.1 &
335 sleep 0.1 | cat &
336
337 jobs -p > tmp.txt
338
339 cat tmp.txt | wc -l # 2 lines, one for each job
340 cat tmp.txt | wc -w # each line is a single "word"
341
342 ## STDOUT:
343 2
344 2
345 ## END
346
347
348 #### No stderr spew when shell is not interactive
349
350 # in interactive shell, this prints 'Process' or 'Pipeline'
351 sleep 0.01 &
352 sleep 0.01 | cat &
353 wait
354
355 ## STDOUT:
356 ## END
357 ## STDERR:
358 ## END
359
360
361 #### YSH wait --all
362 case $SH in dash|bash|mksh) exit ;; esac
363
364 sleep 0.01 &
365 (exit 55) &
366 true &
367 wait
368 echo wait $?
369
370 sleep 0.01 &
371 (exit 44) &
372 true &
373 wait --all
374 echo wait --all $?
375
376 ## STDOUT:
377 wait 0
378 wait --all 1
379 ## END
380
381 ## N-I dash/bash/mksh STDOUT:
382 ## END
383
384 #### YSH wait --verbose
385 case $SH in dash|bash|mksh) exit ;; esac
386
387 sleep 0.01 &
388 (exit 55) &
389 wait --verbose
390 echo wait $?
391
392 (exit 44) &
393 sleep 0.01 &
394 wait --all --verbose
395 echo wait --all $?
396
397 ## STDOUT:
398 wait 0
399 wait --all 1
400 ## END
401
402 ## N-I dash/bash/mksh STDOUT:
403 ## END
404
405 #### Signal message for killed background job
406 case $SH in dash|mksh) exit ;; esac
407
408 sleep 1 &
409 kill -HUP $!
410 wait $! 2>err.txt
411 echo status=$?
412 grep -o "Hangup" err.txt
413 ## status: 0
414 ## STDOUT:
415 status=129
416 Hangup
417 ## END
418 ## STDERR:
419 ## END
420
421 ## N-I dash/mksh STDOUT:
422 ## END