Force bash script to use tee without piping from the command line
Simply add this to the beginning of your script:
exec > >(tee -ia script.log)
That will append all output sent to stdout to the file script.log
, leaving the previous contents in place. If you want to start fresh every time the script is run just add rm script.log
right before that exec
command or remove the -a
from the tee
command.
The -i
option causes tee
to ignore interrupt signals
and may allow tee
to catch a more complete output set.
Add this line to also catch all errors (in a separate file):
exec 2> >(tee -ia scripterr.out)
The spaces between the multiple >
symbols are important.
I couldn't get Dennis' very simple one-liner to work, so here's a far more convoluted method. I'd try his first.
As mentioned, you can use exec to redirect standard error & standard out for the entire script. Like so:
exec > $LOGFILE 2>&1
This will output all stderr and stdout to $LOGFILE.
Now, since you want to have this displayed to the console as well as a logfile, you're also going to have to use a named pipe for exec to write to, and tee to read from.
(Dennis' one-liner technically does this as well, although obviously in a different way) The pipe itself is created with mkfifo $PIPEFILE
. Then do the following.
# Start tee writing to a logfile, but pulling its input from our named pipe. tee $LOGFILE < $PIPEFILE & # capture tee's process ID for the wait command. TEEPID=$! # redirect the rest of the stderr and stdout to our named pipe. exec > $PIPEFILE 2>&1 echo "Make your commands here" echo "All their standard out will get teed." echo "So will their standard error" >&2 # close the stderr and stdout file descriptors. exec 1>&- 2>&- # Wait for tee to finish since now that other end of the pipe has closed. wait $TEEPID
If you want to be thorough, you can create and destroy the named pipe file at the start and end of your script.
For the record, I gleaned most of this from a random guy's very informative blog post: (Archived version)
This is combined version of answer posted by Dennis Williamson earlier. Appends both err & std out to script.log in right order.
Add this line to the beginning of your script:
exec > >(tee -a script.log) 2>&1
Note the space between the >
signs.
Works for me on GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)