Given the pipeline
a | b | c
how might I alter b so that it aborts the pipeline if b generates an error or matches a particular pattern in the input stream?
Given the pipeline
a | b | c
how might I alter b so that it aborts the pipeline if b generates an error or matches a particular pattern in the input stream?
@mosvy's very helpful answer was mostly correct, but has the problem that b() always aborts the pipeline whether or not sed /die/q encounters "die":
Input stream contains "die"
$ b(){ sed /die/q && kill "$BASHPID"; }; printf '%s\n' pass die oops | b | cat; echo "${PIPESTATUS[@]}"
pass
die
0 143 0
Input stream does not contain "die"
$ b(){ sed /die/q && kill "$BASHPID"; }; printf '%s\n' pass oops | b | cat; echo "${PIPESTATUS[@]}"
pass
oops
0 143 0
In @mosvy's version, b() always aborts the pipeline because sed /die/q returns exit code 0 (success) if it encounters "die" or reaches the end of the input stream and so b() always invokes kill "$BASHPID".
In the following version, I correct @mosvy's answer so that b() aborts the pipeline only when it encounters "die" in the input stream:
Input stream contains "die"
b() {
sed '/die/{q 2}' || kill "$BASHPID"
}
# Send "die" to b.
printf '%s\n' pass die oops | b | cat
echo "${PIPESTATUS[@]}"
Output:
pass
die
0 2 0
Input stream does not contain "die"
b() {
sed '/die/{q 2}' || kill "$BASHPID"
}
# Do not send "die" to b.
printf '%s\n' pass oops | b | cat
echo "${PIPESTATUS[@]}"
Output:
pass
oops
0 0 0
Note that in this version of b(), if sed encounters "die", it invokes command q 2 which causes sed to terminate immediately with exit code 2 (failure), and then || to invoke kill "$BASHPID" which terminates b()'s process in the pipeline and aborts the pipeline. (Note that this version requires GNU sed which extends command q so that it accepts an exit code.)
As @mosvy mentions, instead of committing "ritual suicide", b() may simply exit from the process:
b() {
sed '/die/{q 2}' || exit 3
}
# Send "die" to b.
printf '%s\n' pass die oops | b | cat
echo "${PIPESTATUS[@]}"
Output:
pass
die
0 3 0