Probably an ugly trick ...
This is meant (and tested) for "/bin/sh" type of scripts (i.e. currently executed by dash on Debian).
Since elements of a pipeline cannot modify the parent environment, the idea here is to use signalling. Each child process can communicate with its parent process using the USR1 signal (an arbitrary choice). When the parent process (the main script) receives that signal, its signal handler sets a flag variable to 1.
This allows to catch failing commands in any pipeline component (not just the first, as with mispipe
).
## Set flag variable to non-zero
usr1_handler() { LAST_PIPELINE=1; }
## Execute above function when a USR1 signal is received
trap usr1_handler USR1
## Report a failed component in the pipeline
sig_fail() { kill -s USR1 "$$"; }
Example 1: successful pipeline
LAST_PIPELINE=0
{ seq 10 -1 1 || sig_fail; } | { grep -x -e '[2468]' || sig_fail; } | sort
printf 'standard exit status: %u\t\tUSR1 status: %u\n' "$?" "$LAST_PIPELINE"
Output:
2
4
6
8
standard exit status: 0 USR1 status: 0
Example 2: failing pipeline (2nd component)
LAST_PIPELINE=0
{ seq 10 -1 1 || sig_fail; } | { grep -x -e 'foo' || sig_fail; } | sort
printf 'standard exit status: %u\t\tUSR1 status: %u\n' "$?" "$LAST_PIPELINE"
Output:
standard exit status: 0 USR1 status: 1
Example 3: failing pipeline (1st component)
LAST_PIPELINE=0
{ seq 10 -1 foo || sig_fail; } | { grep -x -e '6' || sig_fail; } | sort
printf 'standard exit status: %u\t\tUSR1 status: %u\n' "$?" "$LAST_PIPELINE"
Output:
seq: invalid floating point argument: ‘foo’
Try 'seq --help' for more information.
standard exit status: 0 USR1 status: 1
If you think it is too annoying to remember typing "LAST_PIPELINE=0" before every pipeline occurrences, or if you just want 'syntactic sugar' for shorter code, you could define an alias like :
alias catchfail='LAST_PIPELINE=0; '
and execute your pipeline tests like this :
catchfail { command1 || sig_fail; } | { command2 || sig_fail; } ...
tee
?if gcc -Wall $$f.c -o $$f >$$f.log 2>&1; then cat $$f.log; ./$$f; else vim -o $$f.c $$f.log; fi
(Alternatively, installbash
on Ubunty. It's only an apt-get away.) – Amarillo$ dash -c 'set -e; false | cat'; echo $? 0 $
– Parthenope