Collect the stdout and stderr of a command into a single file and see the output interactively:
some command 2>&1 | tee err
I use this with
make so often that I have a script called
make "$@" 2>&1 | tee err
(and don’t forget, we always use
The output file is named err but would probably be better named ofile (suggested by Nick B in comments). I use err in deference to 15 years of my personal Unix tradition.
The Order of Redirections
Now let’s take pipe out of the equation for a moment and consider redirections alone. On my Mac OS X laptop the command
ls -d /eta /etc produces the following output:
ls: /eta: No such file or directory /etc
The “No such file or directory” message appears on stderr and “/etc” appears on stdout.
You can prove that to yourself by closing one or the other file descriptor. Play around with
ls -d /eta /etc >&-, and
ls -d /eta /etc 2>&- and convince yourself that this is so.
Shell redirections are processed from left to right; we can get the stderr of a command to appear on its stdout and get rid of its stdout entirely:
$ ls -d /eta /etc 2>&1 1>&- ls: /eta: No such file or directory
You might like to think about why this works. fd 2 is redirected to fd 1, meaning output to fd 2 goes to the same place as fd 1 at the time that the redirection was made. Then fd 1 is closed; this doesn’t affect the previous redirection of fd 2.
Doing it the other way round, we get this:
$ ls -d /eta /etc 1>&- 2>&1 -bash: 1: Bad file descriptor
That’s because by the time that it comes to redirect fd 2 to fd 1, fd 1 has been closed and can’t be used for a redirect.
How can we tell that
2>&1 1>&- sends what normally appears on stderr to stdout? Does this convince you:
$ ( ls -d /eta /etc 2>&1 1>&- ) | sed 's/^/*** /' *** ls: /eta: No such file or directory
By borrowing an extra fd you can even swap stderr and stdout over:
$ ls -d /eta /etc 3>&2 2>&1 1>&3 3>&- | sed 's/^/*** /' /etc *** ls: /eta: No such file or directory
Notice that the error message from
ls has gone through the pipe and been transformed by sed, so it must have been sent to stdout. The normal output of ls, “/etc”, has not gone through the pipe, so must’ve been sent to stderr.