I'm trying to understand the reason why echo
behaves differently than echo "Hi"|cat
when used in a bash script, with broken pipe
Behaviour :
echo
immediately terminates the scriptecho "Hi"|cat
the pipeline terminates but the script continues
Sample reproducing steps
script_with_echo.sh :
#!/bin/bash
mkfifo ii
cat<ii >/dev/null & echo "KILL : $!"
exec 3>ii
rm ii
while true; do read LINE; echo "$LINE" >&3; echo "$?">/some/external/file;done
script_with_echo_cat.sh :
#!/bin/bash
mkfifo ii
cat<ii >/dev/null & echo "KILL : $!"
exec 3>ii
rm ii
while true; do read LINE; echo "$LINE"|cat>&3; echo "$?">/some/external/file;done
- run a script on terminal-1 (note
KILL : <PID>
) - input some sample lines to terminal-1 and verify that
0
(success exit code) is being written to/some/external/file
- run
kill -9 <PID>
from terminal-2 - input another sample line on terminal-1
-
- If
script_with_echo.sh
was being executed in step 1, the script immediately terminates (and no error code is written to/some/external/file
) - If
script_with_echo_cat.sh
was being executed in step 1, the script continues normally (and for every subsequent sample line inputs, error code 141 (SIGPIPE
) is being written to/some/external/file
, which is expected)
- If
Why does this different behavior arise?
CodePudding user response:
why echo behaves differently than echo "Hi"|cat when used in a bash script
In the case of echo >&3
when the pipe connect to 3rd file descriptor is closed, then the bash process is killed by SIGPIPE. This is mostly because echo
is a builtin command - it is executed by bash itself without any fork()
ing.
In the case of echo | cat >&3
when the pipe connected to 3rd file descriptor is closed, then the child process cat
is killed by SIGPIPE
, in which case the parent process continues to live, so Bash can handle the exit status.
Compare strace -ff bash -c 'mkfifo ii; cat <ii >/dev/null & pid=$! ; exec 3>ii ; kill $pid ; rm ii ; echo something >&3'
vs ....; /bin/echo something >&3'
.