I am trying to save some logs from bash functions which execute tools (some of them run in subshells). In addition I would like to print all errors to the terminal.
My code leads to a sigpipe and exit code 141 upon hitting ctr-c plus a strange log file. The pipe fail seems to be caused by the redirection of stdout to stderr within the trap, which breaks the stdout stream of the tee command. Interestingly the code terminates as expected with exit code 130 without the redirection used in the trap or the cat
command.
I am still unable to fix and explain the resulting log file. Why are there some echos twice and why are the trap echos written to the file as well?
Why isn't the sigpipe caused earlier by the redirection within the function?
trap '
echo trap_stdout
echo trap_stderr >&2
' INT
fun(){
echo fun_stdout
echo fun_stderr >&2
( sleep 10 | cat )
}
echo > log
fun >> log 2> >(tee -a log)
log file
fun_stdout
fun_stderr
fun_stderr
trap_stdout
EDIT: working example according to oguz ismail answer
exec 3>> log
exec 4> >(tee -ai log >&2)
fun 2>&4 >&3
exec 3>&-
exec 4>&-
fun
's stdout is redirected tolog
before its stderr is redirected to the FIFO created fortee
, thustee
inherits a stdout that is redirected tolog
. I can prove that like so:Changing the order of redirections will fix that. E.g.:
If the trap set for SIGINT is triggered while the shell is still executing
fun
, its perfectly normal that the redirections associated withfun
takes effect.To connect the trap action's stdout and stderr to those of the main shell, you can do:
Or something alike; the idea is making copies of the main shell's stdout and stderr.
Because
tee
is alive whileecho fun_stderr >&2
is being executed. Andsleep
does not write anything to its stdout, so it can not trigger a SIGPIPE.The reason why this script terminates due to a SIGPIPE is that
tee
receives the SIGINT generated by the keyboard as well and terminates before the trap action associated with SIGINT is executed. As a result, while executingecho trap_stderr >&2
, since its stderr is connected to a pipe that has been closed moments ago, the shell receives the SIGPIPE.To avoid this, as already suggested, you can make
tee
ignore SIGINT. You don't need to set an empty trap for that though, the-i
option is enough.