Home > Software design >  wait command behaves differently on Bash and Ash
wait command behaves differently on Bash and Ash

Time:09-15

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 ask wait to wait for a process that's already terminated, it gives the last status, which is 50 as set earlier.
  • In sh (as well as ash, ksh) when you ask wait to wait for a process that's already terminated, it errors with test.sh: line 9: wait: pid 27016 is not a child of this shell which is 127.

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:

  1. 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 to wait "${!}" make the exit code change to 127, with the exception of echo command.

this looks like a bug that is fixed in NetBSD sh and FreeBSD sh but not in busybox sh, dash, and gwsh.

  • Related