Problem: stderr
redirection is not working.
Before we start, let’s define a simple function that writes data to stderr
instead of stdout
.
1 |
$ echostderr () { echo "$@" 1>&2; } |
What the echostderr
function will do is to print whatever arguments that are passed to it to stderr
.
1 2 |
$ echostderr "printing to stderr" printing to stderr |
Now, let’s say that we want to redirect stderr
and stdout
output to a file, how should we do it? Well, we redirect stderr
to stdout
and then redirect stdout
to a file? Well, let’ see.
1 2 3 4 |
$ echostderr "printing to stderr" 2>&1 > out.log printing to stderr $ cat out.log $ |
Well, it looks like the stderr
output was never redirected to the out.log
file. Instead, it was sent to the terminal.
What went wrong? Well, the reason is simple. For multiple redirections, the order is important. They’re evaluated from left to right. If you want to redirect stderr
or both stderr
and stdout
to the same file, this is the wrong way to do it.
Let’s look at why it is not working.
- Initially, both
stderr
andstdout
point to the terminal. - Then
2>&1
redirectsstderr
tostdout
, which points to the terminal. So effectively,stderr
is not redirected at all. Or, it was redirected from the terminal back to the terminal again. - Lastly,
> out.log
will redirectstdout
from the terminal toout.log
file. Whilestdout
got redirected to out.log,stderr
is still pointing to the terminal.
To make it work, we have to swap the order of redirection.
1 2 3 |
$ echostderr "printing to stderr" > out.log 2>&1 $ cat out.log printing to stderr |
So, what happens now is:
- Both
stderr
andstdout
point to the terminal initially. stdout
is redirected to “out.log
” file.stderr
is redirected tostdout
, which is currently pointing to the “out.log
” file.