I\'m using a pipe of several commands in bash. Is there a way of configuring bash to terminate all commands in the whole pipeline immediately should one of the commands fail
The following code seems to work by Dash, but EXIT traps within pipe do not work in Bash; maybe it is a bug in Bash.
#!/bin/sh
echo PID of the shell: $$
trap 'echo In INT trap >&2; trap - EXIT INT; kill -s INT $$' INT
(
# now in subshell
pidofsubshell=$(exec sh -c 'echo "$PPID"')
# $BASHPID can be used as a value, when using Bash
echo PID of subshell: $pidofsubshell
fifo=$(mktemp -u); shells=$(mktemp) childs=$(mktemp)
mkfifo $fifo
trap 'echo In sub trap >&2; rm $fifo $shells $childs; trap - EXIT; exit' EXIT HUP TERM INT ALRM
pipe_trap() {
code=$?
echo In sub sub trap $1 >&2
echo $1 $code >> $fifo
}
{ trap 'echo In pipe signal trap >&2; kill $(cat $childs $shells) 2>/dev/null' INT HUP TERM ALRM
{ trap 'pipe_trap 1' EXIT
sleep 30; } \
| { trap 'pipe_trap 2' EXIT
sleep 50 & sleep 2; } \
| { trap 'pipe_trap 3' EXIT
sleep 40; } &
}
echo ps tail:
ps xao pid,ppid,pgid,sid,command | head -n 1
ps xao pid,ppid,pgid,sid,command | tail -n 15
ps -o pid= --ppid $pidofsubshell | head -n -2 > $shells # strip pids of ps and head
echo shells:
cat $shells
while read -r ppid; do ps -o pid= --ppid $ppid; done <$shells >$childs
echo childs of above
cat $childs
{
IFS=' ' read -r id exitcode
echo Pipe part nr. $id terminated first with code $exitcode\; killing the remaining processes.
kill $(cat $childs $shells) 2>/dev/null
} < $fifo
)
echo
echo After subshell:
ps xao pid,ppid,pgid,sid,command | head -n 1
ps xao pid,ppid,pgid,sid,command | tail -n 15