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?
CodePudding user response:
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:
sleep 3 && exit 50& # <-- "&" sends to background
The second call to sleep
is not executed as a background command.
sleep 1 # <-- This is missing the "&" to send it to the background
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.
- In
bash
, when you askwait
to wait for a process that's already terminated, it gives the last status, which is50
as set earlier. - In
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
.
CodePudding user response:
bash behaves the same way as busybox sh/dash in POSIX mode,
$ set -o posix
$ sleep 3 && exit 42 &
[1] 8573
$ wait $!; echo $?
[1] Done(42) sleep 3 && exit 42
42
$ wait $!; echo $?
bash: wait: pid 8573 is not a child of this shell
127
and this is mentioned in the official bash POSIX mode description as follows:
- Bash removes an exited background process's status from the list of such statuses after the 'wait' builtin is used to obtain it.
And wrt
In
ash
, all commands put between 2 calls towait "${!}"
make the exit code change to 127, with the exception ofecho
command.
this looks like a bug that is fixed in NetBSD sh and FreeBSD sh but not in busybox sh, dash, and gwsh.