The following toy script (tmp.sh
) exits with code 0 even if the process sent to the named pipe fails. How can I capture the non-zero exit code from the named pipe? Or more in general, the fact that something has gone wrong?
#!/bin/bash
set -eo pipefail
mkfifo mypipe
FOOBAR > mypipe &
cat mypipe
Run and check exit code:
bash tmp.sh
tmp.sh: line 6: FOOBAR: command not found
echo $? # <- Exit code is 0 despite the "command not found"!
You need to capture process id of background process and wait
for it to set the correct exit status:
#!/bin/bash
set -eo pipefail
rm -f mypipe
mkfifo mypipe
FOOBAR > mypipe &
# store process id of above process into pid
pid=$!
cat mypipe
# wait for background process to complete
wait $pid
Now when you run it:
bash tmp.sh
tmp.sh: line 6: FOOBAR: command not found
echo $?
127
If you need to be able to catch errors and apply specific behavior, a trap can be your friend. This code prints itself, so I just post a run here:
$: tst
+ trap 'x=$?; echo "$x@$0:$LINENO"; exit $x' err
+ rm -f mypipe
+ mkfifo mypipe
+ pid=6404
+ cat mypipe
+ cat ./tst
#! /bin/env bash
set -x
trap 'x=$?; echo "$x@$0:$LINENO"; exit $x' err
#set -eo pipefail
rm -f mypipe
mkfifo mypipe
cat $0 >mypipe &
pid=$!
cat mypipe
wait $pid
fubar >mypipe &
pid=$!
cat mypipe
wait $pid
echo done
+ wait 6404
+ pid=7884
+ cat mypipe
+ fubar
./tst: line 16: fubar: command not found
+ wait 7884
++ x=127
++ echo 127@./tst:19
127@./tst:19
Note the trap 'x=$?; echo "$x@$0:$LINENO"; exit $x' err
line.
It sets x to the last error code, which will be whatever triggered it. Then it prints the code, the filename, and the line number it is currently executing (before the trap) and exits the program with the error code. This actually triggers on the wait
. It causes it to bail before continuing the echo at the bottom.
It works with or without the set -eo pipefail
.