I'd like to provide an optional logging parameter in a bash script, and would like to use exec
to tee
a pipe from the beginning. However, opening the tee
process is causing the script to hang, I believe because stdout is not closed:
# Output to a log file, if set
if [[ $OPT_LOG ]]; then
exec > >(tee -a $OPT_LOG)
fi
I've attempted to close with:
exec >&-
But it still hangs - is there another way to properly close tee
so the script will exit properly at the end of execution?
It seems like, for some reason, using tee
stops the prompt ($PS1
) from appearing because the shell script has not exited. As a workaround, I generally use a short sleep
after calling tee
.
#!/bin/bash
exec > >(tee -a mylog)
sleep .1
# my code
Converting comments into an answer, with minor edits.
I noted:
The following code exits OK for me on Mac OS X 10.10.3.
OPT_LOG=file.name if [[ $OPT_LOG ]] then exec > >(tee -a $OPT_LOG) fi for ((i = 0; i < 10; i++)) do echo "Logging message $i at $(date)" sleep 1 done
Your problem is probably in the code you've not shown. What commands are you running? What do you get from
bash -x yourscript.sh
?
And chatraed observed
If you remove the sleep and date calls from your example, the script does not exit properly any more, as told by Andrew:
OPT_LOG=file.name; if [[ $OPT_LOG ]]; then exec > >(tee -a $OPT_LOG); fi; for ((i = 0; i < 10; i++)); do echo "Logging message $i"; done
And I responded:
Now that's an interesting observation! I can reproduce your result.
I experimented a bit:
pwd
before the for loop with 'just the echo', and that didn't affect things (but pwd
is probably a Bash built-in).bash -c 'exit 0'
(which is not a built-in) and the code terminated OK.> >(tee -a $OPT_LOG &)
and the output didn't appear — on screen or in the file. (I find this surprising, but it was an attempted workaround, not a major part of the work.)My impression is that Andrew has found a bug in Bash that could viably be reported. (See the Bash manual on Reporting Bugs for how to do that.) I don't think that not exiting simply because no external commands have been executed since the I/O redirection is OK. I can confirm that Apple's Bash 3.2.57 has the problem; so does Bash 4.3.27 (which I built for myself so it is patched with the fixes to the ShellShock bug).
It is relatively unusual that a shell script does not invoke any external command, and invoking any external command after the exec redirection seems to suppress the bug.
It also confirms that chatraed's workaround works, albeit more slowly than minimally necessary. For production use, I'd choose sleep 0
, which is most of a tenth of a second faster than sleep 0.1
. And sleeping for a fraction of a second only works on some systems; classically (and according to POSIX), sleep
does not sleep for fractional seconds. OTOH, if you write sleep 0.1
, on systems without support for fractional seconds, including the leading 0
probably makes it sleep for zero seconds anyway; writing .1
might or might not have the same effect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With