On Tue, Jun 01, 2021 at 08:18:09PM +1000, Dave Jennings wrote:
But if I add a pipeline to the initial command:
#!/bin/bash
timeout 5 sleep 10 | cat &
Some background:
In sh, with a pipeline, you only see the exit status of the last
command. The other exit statuses are simply not available.
Bash adds the PIPESTATUS array variable which exposes the exit statuses
of all the commands in a pipeline, but it only works with foreground
pipelines.
Now you've gone and made a *background* pipeline, and there's simply
no support for exposing the exit statuses of the internal pieces of
one of those.
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
So now you're trying to hack together your *own* support for extracting
the exit statuses of internal pieces of background pipelines.
wait $timeout_pid
echo "exit code: $?"
The wait command only works on direct child processes of the shell, a.k.a.
"asynchronous commands". In the case where your asynchronous command is
a pipeline, we fall back to the original sh feature set. The exit status
of your asynchronous command is that of the last command in the pipeline,
and the other commands' exit statuses are simply discarded. There's no
PIPESTATUS variable for this case, at least not in the parent shell. All
of the action is taking place in the subshell.
So, really, what you want to do is extract the exit statuses of all the
commands in a *background* pipeline, and expose them to the parent shell.
We just need to come up with a way to do that.
The most obvious way is to use a temp file.
=======================================================================
unicorn:~$ cat foo
#!/bin/bash
unset tempfile
trap '[[ $tempfile ]] && rm -f "$tempfile"' EXIT
tempfile=$(mktemp) || exit
echo "Starting pipeline"
{
false | true | sleep 2 | exit 14 | echo foo | cat
echo "${PIPESTATUS[@]}" > "$tempfile"
} &
wait
echo "Pipeline finished. Results:"
cat "$tempfile"
unicorn:~$ ./foo
Starting pipeline
foo
Pipeline finished. Results:
1 0 0 14 0 0
=======================================================================
The parent shell process can't see the PIPESTATUS variable of the child
subshell, but it can read the results from the temp file after the child
has written them there.
If you think you can come up with a better alternative, by all means,
go for it. This is what I would use.