There are two side effects of running a command asynchronously in a non-interactive shell that make A
and A & wait "$!"
different:
SIGINT and SIGQUIT are ignored for A
. If you press Ctrl+C, whilst running bash -c 'sleep 1000 & wait "$!"'
, you'll notice bash
is terminated, but not sleep
.
A
's stdin is redirected to /dev/null
:
$ bash -c 'readlink /dev/fd/0'
/dev/pts/4
$ bash -c 'readlink /dev/fd/0 & wait "$!"'
/dev/null
Another difference is that in A | B & wait "$!"
(where $!
contains the pid of the process eventually running B
), the exit status of A
is lost ($PIPESTATUS
will contain only one entry, the exit status of wait
, which will be that of B
if the pipefail
option is not set).
In zsh
, in A | B
, zsh
waits for both A
and B
, but in A | B & wait $!
only waits for B
(and the exit status of A
is lost even with pipefail
).
Another difference is that if a signal is delivered to the shell, it will be handled straight away and wait
will return (even if the process it's waiting for is not finished).
Compare:
$ bash -c 'trap "echo Ouch" TERM; sleep 10 & wait "$!"; echo "$?"' & sleep 1; kill "$!"
[1] 13749
Ouch
143
Where Ouch
is output as soon as SIGTERM
is sent to bash
(and sleep 10
carries on running after bash
terminates) with:
$ bash -c 'trap "echo Ouch" TERM; sleep 10; echo "$?"' & sleep 1; kill "$!"
[1] 13822
$ Ouch 6:11
0
[1] + done bash -c 'trap "echo Ouch" TERM; sleep 10; echo "$?"'
Where Ouch
is output only after sleep 10
returns.
Whether any of those side effects were wanted by the script author is another matter. You'll notice many other mistakes in that script, it's very well possible that whoever wrote that script didn't know much about shell scripting.
sed
or similar on the file directly, because looping over the lines is what they'd do in Python or C)wait
is (and has to be) a builtin command, so you can't see it in the output ofps
.