If you have been shell scripting for a while, you may have seen 1>&2
or 2>&1
idioms. Ex:
SOME_COMMAND > /dev/null 2>&1
This article will explain what that strange-looking 2>&1
means.
TL;DR:
2>&1
means redirect the stderr (>2
) to where stdout is being redirected to (&1
).
Before we start, I want to go over a basic concept of file descriptors. There are 3 file descriptors in UNIX and each is associated with a number:
| Name | Short Name | File Descriptor Number| Description |
| --------------:|:-------------:| ---------------------:| ---------------------:
| Standard In | stdin
| 0 | Keyboard Input |
| Standard Out | stdout
| 1 | Console Output |
| Standard Error | stderr
| 2 | Console Error Output |
We won't cover stdin
in this article, but we will talk about stdout
and stderr
. Let's go!
stdout
When you execute a command, for example: ls
. You will see the result of your command displayed on your screen. In this case, I see:
> ls
README.md components src
Let's do one more:
> echo "hello"
hello
These are examples of stdout
. They all have file descriptor value of 1. If you want to learn more about file descriptors, check out resources at the end of this post.
stdout
redirection
You can redirect your stdout
with >
.
> echo "Hello stdout" > result.txt
> cat result.txt
Hello stdout
We no longer see "Hello stdout" after running echo
. This is because instead of "Hello stdout"
being displayed to console, it gets redirected to result.txt
. The file result.txt
contains our echo
output: "Hello stdout"
.
Let's try one more:
> ls > result.txt
> cat result.txt
README.md
component
src
This time you see the content of ls
inside result.txt
.
My point is, everything you see on your screen (that is not error) - every stdout
- can be redirected with >
.
By the way, >
is actually a shorthand for 1>
. If you do:
> echo "Hello redirection" 1> result.txt
> cat result.txt
Hello redirection
You get the same functionality using 1>
as with >
. Keep this in mind.
stderr
Sometimes we may encounter error running a command:
> cat filedoesntexist.txt
cat: filedoesntexist.txt: No such file or directory
> ls idontexist
ls: idontexist: No such file or directory
Let's compare running two different commands. Replace something_that_exists
below with an actual file in your current directory.
> cat something_that_exists
> cat something_that_doesnt_exist
Although they each return some sort of output, your computer doesn't interpret these two outputs the same way. cat something_that_exists
has file descriptor of 1 and cat something_that_doesnt_exist
has file descriptor of 2.
stderr
redirection
Let me show you how they're different. If we try to redirect a bad cat
(😺 pun not intended):
> cat filedoesntexist > result.txt
cat: filedoesntexist: No such file or directory
> cat result.txt
You see cat: filedoesntexist: No such file or directory
error displayed on your console and result.txt
is empty. Our redirection redirects nothing.
This is because when we perform cat filedoesntexist
, we get a stderr
and not stdout
. When we tried to redirect stdout
to result.txt with > result.txt
, there is no stdout
to be redirected. To redirect stderr
, we need to use stderr
redirect, not stdout
redirect. To redirect stderr
, we use 2>
.
> cat filedoesntexist 2> result.txt
> cat result.txt
cat: filedoesntexist: No such file or directory
This looks better. We no longer sees the error output when running cat filedoesntexist
and our result.txt
contains cat: filedoesntexist: No such file or directory
error string. We have successfully redirected our bad cat
😸!
So we learned that there are at least 2 redirections: >
and 2>
. The former redirects normal outputs, the latter redirects error outputs.
To reinforce our knowledge, what do you think will happen if we do echo
and use 2>
redirection? Don't read further. Spend some time to think about this. When you're ready, read on.
. . . . . . . . . .
> echo "Hello Cat" 2> result.txt
Hello Cat
> cat result.txt
We see Hello Cat
being echoed to our console and result.txt
is blank, because we are redirecting stderr
from our echo
. Since our echo
doesn't return any error, nothing gets redirected to result.txt
.
stdout
, stderr
, and 2>&1
Let's do one last example.
> ls myDir > result.txt 2> result.txt
This will redirect stdout
and stderr
from running ls myDir
to result.txt
. This way, if myDir
exists, it will redirect the output to result.txt
and if myDir
doesn't exist, it will redirect the error message to result.txt
. User will not see any output whether the command works or not. It's a win-win.
This feels a bit too long, doesn't it? Luckily we can shorten it:
> ls myDir > result.txt 2>&1
Hey, look at that! Our 2>&1
idiom. It means redirect any stderr (2>
) to the same place we are redirecting stdout (&1
).
That's right! ls myDir > result.txt 2>&1
is the same as ls myDir > result.txt 2> result.txt
. Think about this. Internalize it.
You can mix file descriptors, for example, what do you think this does?
> ls myDir 2> result.txt 1>&2
You might've guessed it now: 1>&2
means "redirect the stdout
to where stderr
is being redirected to".
So what do people use 2>&1
for? I have seen people running the command we see above (ex: Crontab quick reference (disable email)):
> CMD > /dev/null 2>&1
The script above redirects the output and error messages from whatever CMD
you're running to /dev/null
(if you're wondering what is /dev/null
, it is a special file that discards everything written to it. I think of it like a black hole/ paper shredder).
This is a good place to stop.
I hope that makes sense so far. If not, I suggest either reread it or read some from resources below. Take your time understanding this, especially if it is new. It took me a while to understand it.
Thank you so much for reading! Appreciate it. Now go write some cool scripts with this!