Capture non-zero exit code from named pipe

2019-07-19 02:02发布

问题:

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"!

回答1:

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


回答2:

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.