10

According to the Bash 4.4 changelog:

https://lists.gnu.org/archive/html/info-gnu/2016-09/msg00008.html

There are a few incompatible changes between bash-4.3 and bash-4.4. Bash now retains the exit status only of asynchronous jobs, as opposed to all jobs. This means that it is not possible to use `wait' to retrieve the status of a previously-completed synchronous command.

https://fossies.org/diffs/bash/4.3.46_vs_4.4/CHANGES-diff.html

Bash only adds asynchronous commands to the table of background pids whose status it remembers, to avoid it growing too large during scripts that create and reap large numbers of child processes. This means that `wait' no longer works on synchronous jobs, but $? can be used to get the exit status in those cases.

I've already been bitten by some other breaking changes between 4.3 and 4.4 but I don't know how to write an example which tests this particular change.

What is the difference between a synchronous job versus an asynchronous one in Bash and where did it store a table of pids to be queried by wait?

2
  • 5
    This is getting very intriguing, almost annoying. I wish we could talk to the one who wrote that change log. Jan 14, 2017 at 22:08
  • The use of synchronous and asynchronous seems the wrong way around to be. Therefore the log file is wrong in some way, or the meaning is not what I expected (asynchronous ≠ background). Jan 16, 2017 at 18:56

1 Answer 1

3
+100

Example:

4.3

bash-4.3$ (echo "$BASHPID"; exit 123)
5358
bash-4.3$ wait 5358; echo "$?"
123

4.4

bash-4.4$ (echo "$BASHPID"; exit 123)
12171
bash-4.4$ wait 12171
bash: wait: pid 12171 is not a child of this shell

You can no longer use wait to get the exit status of that subshell that run in foreground (synchronously). foreground refers to jobs of interactive shells, but the same applies for commands run in non-interactive shells.

Note that it also applies to background jobs that are later put in foreground with fg:

bash-4.4$ (sleep 10; exit 123) &
[1] 12857
bash-4.4$ fg
( sleep 10; exit 123 )
bash-4.4$ wait 12857
bash: wait: pid 12857 is not a child of this shell

With bash-4.3 and before bash would remember the exit status of every past background and foreground command. That would not be useful for foreground commands as usually, you don't know their pid in the script and also in things like:

cmd1 &
...
cmd2
wait "$!"

cmd1's pid could very well have been reused for cmd2. In that case wait "$!" would get you the exit status of cmd2 instead of cmd1. Recording the pid of only asynchronous commands slightly reduces the risk of wait giving you the exit status of the wrong command (beside the performance issue mentioned by @Christopher).

2
  • This makes sense as well as establishes that the 'table' mentioned in the changelog would have been to map PIDs to exit statuses. A synchronous process could generate a very large table at runtime and the assumption is that you would generally be interacting with these processes by handling $? instead of querying the PID. An asynchronous process, in contrast, would need to store its exit status in the table, otherwise there would be no way to extract it again later; as subshells each have their own environment.
    – Zhro
    Jan 17, 2017 at 19:45
  • Now it makes so much more sense. Great answer! Jan 18, 2017 at 3:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .