Given the following simple snippet, saved in a file named test.sh
:
sleep 3 && exit 50&
echo "Wait for ${!} for the first time."
wait "${!}"
echo "Exit code is: ${?}"
sleep 1 # this line makes a difference
echo "Wait for ${!} for the second time."
wait "${!}"
echo "Exit code is: ${?}"
Running the file using bash test.sh
gives the following output:
Wait for 40781 for the first time.
Exit code is: 50
Wait for 40781 for the second time.
Exit code is: 50
While running the file using sh test.sh
(I tried on both Ubuntu dash and BusyBox ash) gives the following output:
Wait for 40773 for the first time.
Exit code is: 50
Wait for 40773 for the second time.
Exit code is: 127
In ash
, all commands put between 2 calls to wait "${!}"
make the exit code change to 127, with the exception of echo
command. Also, with the sleep 1
line removed, running the file using sh test.sh
gives exit code 50
, but manually copying all lines and pasting to the sh
terminal gives 127
again.
I really don’t understand this behavior, and it causes me quite a lot of headache debugging my code. Can someone explain?
2
Answers
According to this, the
$!
variable represents "The PID of the most recent background command". In the example above, there is one and only one background command:The second call to
sleep
is not executed as a background command.The difference in behavior is with the
wait
command, which is a shell built-in. Shell built-ins can and will change in behavior between different shell implementations.bash
, when you askwait
to wait for a process that’s already terminated, it gives the last status, which is50
as set earlier.sh
(as well asash
,ksh
) when you askwait
to wait for a process that’s already terminated, it errors withtest.sh: line 9: wait: pid 27016 is not a child of this shell
which is127
.bash behaves the same way as busybox sh/dash in POSIX mode,
and this is mentioned in the official bash POSIX mode description as follows:
And wrt
this looks like a bug that is fixed in NetBSD sh and FreeBSD sh but not in busybox sh and dash.