Technology
What Does 2>&1 Mean? Shell Redirection, Explained
What Does 2>&1 Mean? Shell Redirection, Explained
If you've spent any time in a terminal, you've typed something like this:
./backup.sh > backup.log 2>&1
Probably because a Stack Overflow answer told you to. It works, so you move on. But 2>&1 looks like line noise, and it has a nasty habit of not working when you put it in a slightly different spot.
Here's what it actually means, character by character.
The one-sentence answer
2>&1 means "send file descriptor 2 (errors) to wherever file descriptor 1 (normal output) is currently going."
That's it. In practice, it merges a command's error messages into its regular output, so both end up in the same file or the same pipe.
The pieces
To read it, you need to know that every program starts with three numbered channels — file descriptors:
- 0 is standard input
- 1 is standard output — normal results
- 2 is standard error — error messages and warnings
They're separate on purpose. If you run grep pattern *.txt > matches.txt and one of the files is unreadable, you want the matches in the file and the "Permission denied" on your screen — not an error message mixed into your results.
Now the syntax:
2— the file descriptor being redirected (stderr)>— redirect it&1— to file descriptor 1
The & is the important part. Without it, 2>1 means "send errors to a file named 1." You'll find these stray files called 1 sitting in people's home directories, left behind by exactly this typo. The & tells the shell the next thing is a file descriptor number, not a filename.
Why order matters
This is where people get bitten. These two commands look almost the same:
command > out.txt 2>&1 # both stdout and stderr go to out.txt
command 2>&1 > out.txt # only stdout goes to out.txt; errors still hit the terminal
The reason: redirections run left to right, and 2>&1 copies where fd 1 points at that moment. It doesn't create a permanent link.
Walk through the first one:
> out.txt— fd 1 now points at out.txt.2>&1— fd 2 copies fd 1, so it also points at out.txt. Both go to the file.
Now the second one:
2>&1— fd 2 copies fd 1, which is still your terminal. So errors go to the terminal.> out.txt— fd 1 moves to out.txt. fd 2 doesn't follow; it already made its copy.
Think of it like "set A equal to B" in code. Changing B afterward doesn't change A.
With pipes
Pipes are the one place where order seems to break this rule:
command 2>&1 | less
This sends both output and errors into less, even though 2>&1 comes first. That's because the shell connects the pipe before it processes any redirections on the command. By the time 2>&1 runs, fd 1 already points into the pipe, so fd 2 copies that.
Without 2>&1, error messages skip the pipe entirely and print straight to your terminal — which is why command | grep something sometimes shows lines that obviously don't match your pattern. Those lines aren't going through grep at all.
The patterns you'll actually use
# Log everything a cron job prints, errors included
/usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
# Throw away errors, keep normal output
find / -name "*.conf" 2>/dev/null
# Throw away everything
noisy-command > /dev/null 2>&1
# Search through errors as well as output
make 2>&1 | grep -i warning
# Print your own error message to stderr from a script
echo "Error: config file not found" >&2
That last one is the mirror image: >&2 is short for 1>&2 — send stdout to wherever stderr is going. It's how well-behaved scripts keep their error messages out of the data stream.
The shortcuts (and where they break)
Bash has shorter versions:
command &> out.txt # same as: command > out.txt 2>&1
command |& less # same as: command 2>&1 | less
They're nice to type, but they're Bash features, not standard shell syntax. Run a script with &> under a strict POSIX shell like dash (which is /bin/sh on Debian and Ubuntu), and it doesn't fail — it does something different. dash reads command &> out.txt as "run command in the background, then redirect nothing into out.txt." Your command runs, its output goes to the terminal, and out.txt ends up empty.
That's a nasty bug to chase in a cron job. If your script starts with #!/bin/sh, stick with > file 2>&1. It works everywhere.
What's actually happening underneath
There's no special trick here. The shell turns 2>&1 into a single system call, dup2(1, 2): "make fd 2 a copy of fd 1." Every n>&m you'll ever write is just that call with different numbers. It's the same file descriptor machinery that lets everything be a file in the first place — redirection doesn't care whether fd 1 is a terminal, a file, or a pipe.
There's a well-known bit of Unix history behind the split, too. As the story usually goes, early Unix had no separate error stream, and error messages from jobs sent to the lab's phototypesetter ended up typeset right into the output. Standard error was added so errors would have somewhere to go besides your results.
Why it's worth knowing
2>&1 is one of those things you can copy forever without understanding. But once you see that it's just "point this number where that number points, right now," the confusing cases explain themselves: why order matters, why errors slip past grep, why your cron log is empty.
And it's a small, satisfying example of the Unix idea that keeps paying off: a few simple pieces — numbered channels, copy one to another — combining into something you use every day.