One of the neat tricks of
exec is that you can use it to redirect all output from a shell. If you take advantage of this inside of a script you can easily send all your output to a file, or even
#!/bin/bash # redirect STDOUT to a file (note the single > -- this will truncate /tmp/outfile) exec 1> /tmp/outfile echo Now all STDOUT from each subsiquent command will echo be redirected to /tmp/outfile echo but not STDERR >&2 # redirect STDERR to STDOUT and append (note the double >>) both to /tmp/outfile exec 1>> /tmp/outfile 2>&1 echo now we get STDERR too >&2 # We can also turn off all output echo 1>&- echo 2>&- echo Now you can\'t hear me!
Now if you want to redirect all the output to another command you have to be a bit craftier. You can't simply use an unnamed pipe after
exec to redirect output to another command's
STDIN -- all this will accomplish is sending all of
exec's output to the second command, and
exec doesn't produce any output.
In this example we use a named pipe. We set our our second command's
STDIN to the named pipe. In this case
logger which will send all the output to
syslog -- and then direct all output to the named pipe using
#!/bin/bash # location of named pipe named_pipe=/tmp/$$.tmp # remove pipe on the exit signal trap "rm -f $named_pipe" EXIT # create named pipe mknod $named_pipe p # start logger process in background with STDIN coming from named pipe # also tell logger to append the script name to the syslog messages # so we know where they came from logger <$named_pipe -t $0 & # or maybe you wanted a log file and output to STDOUT # tee <$named_pipe /tmp/outfile & # redirect stderr and stdout to named_pipe exec 1>$named_pipe 2>&1 echo STDOUT captured echo STDERR captured >&2
You can also use this trick to make your script's a little smarter about where they send their output. Perhaps you want the output to go to
STDOUT if run from a terminal, but sent to a file when run by
#!/bin/bash # test if fd 1 (STDOUT) is NOT associated with a terminal if [ ! -t 1 ] ; then # redirect STDOUT to a file (note the >> -- this will append to /tmp/outfile) exec 1>> /tmp/outfile fi echo Hello world!
If you want to switch back and forth you can also save
STDERR to a higher file descriptor and then restore them to their original file descriptor when you're done:
#!/bin/bash # save stdout to fd 3 and redirect output to outfile exec 3>&1 >> /tmp/outfile echo output to file # and now restore stdout from fd 3 -- and close fd 3 exec 1>&3 >&3- echo back to stdout ( # or redirect within a subshell and only this output is redirected exec >> /tmp/outfile echo more output to file ) # and we're back echo out of the subshell output returns to stdout # note how it effects only the subshell # -- if you ran these exec command from your shell: # $ exec > /tmp/save_commandline # your shell would redirect stdout to a file, kind of confusing but if you # source a script that uses exec and a named pipe directed to tee you could # make a version of the script command