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