Home > Software design >  Different behavior with echo vs echo|cat when reading to / writing from FIFOs (pipes)
Different behavior with echo vs echo|cat when reading to / writing from FIFOs (pipes)

Time:09-16

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 :

  1. echo immediately terminates the script
  2. echo "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
  1. run a script on terminal-1 (note KILL : <PID>)
  2. input some sample lines to terminal-1 and verify that 0 (success exit code) is being written to /some/external/file
  3. run kill -9 <PID> from terminal-2
  4. 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)

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'.

  • Related