In the shell, what does " 2>&1 " mean?

1,409,419

Solution 1

File descriptor 1 is the standard output (stdout).
File descriptor 2 is the standard error (stderr).

Here is one way to remember this construct (although it is not entirely accurate): at first, 2>1 may look like a good way to redirect stderr to stdout. However, it will actually be interpreted as "redirect stderr to a file named 1". & indicates that what follows and precedes is a file descriptor and not a filename. So the construct becomes: 2>&1.

Consider >& as redirect merger operator.

Solution 2

echo test > afile.txt

redirects stdout to afile.txt. This is the same as doing

echo test 1> afile.txt

To redirect stderr, you do:

echo test 2> afile.txt

>& is the syntax to redirect a stream to another file descriptor - 0 is stdin, 1 is stdout, and 2 is stderr.

You can redirect stdout to stderr by doing:

echo test 1>&2 # or echo test >&2

Or vice versa:

echo test 2>&1

So, in short... 2> redirects stderr to an (unspecified) file, appending &1 redirects stderr to stdout.

Solution 3

Some tricks about redirection

Some syntax particularity about this may have important behaviours. There is some little samples about redirections, STDERR, STDOUT, and arguments ordering.

1 - Overwriting or appending?

Symbol > means redirection.

  • > means send to as a whole completed file, overwriting target if exist (see noclobber bash feature at #3 later).
  • >> means send in addition to would append to target if exist.

In any case, the file would be created if they not exist.

2 - The shell command line is order dependent!!

For testing this, we need a simple command which will send something on both outputs:

$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

(Expecting you don't have a directory named /tnt, of course ;). Well, we have it!!

So, let's see:

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1

$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory

The last command line dumps STDERR to the console, and it seem not to be the expected behaviour... But...

If you want to make some post filtering about standard output, error output or both:

$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'

$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->

Notice that the last command line in this paragraph is exactly same as in previous paragraph, where I wrote seem not to be the expected behaviour (so, this could even be an expected behaviour).

Well, there is a little tricks about redirections, for doing different operation on both outputs:

$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2  2>&1  | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan  7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory

Note: &9 descriptor would occur spontaneously because of ) 9>&2.

Addendum: nota! With the new version of (>4.0) there is a new feature and more sexy syntax for doing this kind of things:

$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory

And finally for such a cascading output formatting:

$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
     1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

Addendum: nota! Same new syntax, in both ways:

$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
     1  O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

Where STDOUT go through a specific filter, STDERR to another and finally both outputs merged go through a third command filter.

2b - Using |& instead

Syntax command |& ... could be used as an alias for command 2>&1 | .... Same rules about command line order applies. More details at What is the meaning of operator |& in bash?

3 - A word about noclobber option and >| syntax

That's about overwriting:

While set -o noclobber instruct bash to not overwrite any existing file, the >| syntax let you pass through this limitation:

$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:15 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:19 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:21 CET 2013

The file is overwritten each time, well now:

$ set -o noclobber

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

Pass through with >|:

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

Unsetting this option and/or inquiring if already set.

$ set -o | grep noclobber
noclobber           on

$ set +o noclobber

$ set -o | grep noclobber
noclobber           off

$ date > $testfile ; cat $testfile
Mon Jan  7 13:24:27 CET 2013

$ rm $testfile

4 - Last trick and more...

For redirecting both output from a given command, we see that a right syntax could be:

$ ls -ld /tmp /tnt >/dev/null 2>&1

for this special case, there is a shortcut syntax: &> ... or >&

$ ls -ld /tmp /tnt &>/dev/null

$ ls -ld /tmp /tnt >&/dev/null

Nota: if 2>&1 exist, 1>&2 is a correct syntax too:

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

4b- Now, I will let you think about:

$ ls -ld /tmp /tnt 2>&1 1>&2  | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

$ ls -ld /tmp /tnt 1>&2 2>&1  | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

4c- If you're interested in more information

You could read the fine manual by hitting:

man -Len -Pless\ +/^REDIRECTION bash

in a console ;-)

Solution 4

I found this brilliant post on redirection: All about redirections

Redirect both standard output and standard error to a file

$ command &>file

This one-liner uses the &> operator to redirect both output streams - stdout and stderr - from command to file. This is Bash's shortcut for quickly redirecting both streams to the same destination.

Here is how the file descriptor table looks like after Bash has redirected both streams:

Enter image description here

As you can see, both stdout and stderr now point to file. So anything written to stdout and stderr gets written to file.

There are several ways to redirect both streams to the same destination. You can redirect each stream one after another:

$ command >file 2>&1

This is a much more common way to redirect both streams to a file. First stdout is redirected to file, and then stderr is duplicated to be the same as stdout. So both streams end up pointing to file.

When Bash sees several redirections it processes them from left to right. Let's go through the steps and see how that happens. Before running any commands, Bash's file descriptor table looks like this:

Enter image description here

Now Bash processes the first redirection >file. We've seen this before and it makes stdout point to file:

Enter image description here

Next Bash sees the second redirection 2>&1. We haven't seen this redirection before. This one duplicates file descriptor 2 to be a copy of file descriptor 1 and we get:

Enter image description here

Both streams have been redirected to file.

However be careful here! Writing

command >file 2>&1

is not the same as writing:

$ command 2>&1 >file

The order of redirects matters in Bash! This command redirects only the standard output to the file. The stderr will still print to the terminal. To understand why that happens, let's go through the steps again. So before running the command, the file descriptor table looks like this:

Enter image description here

Now Bash processes redirections left to right. It first sees 2>&1 so it duplicates stderr to stdout. The file descriptor table becomes:

Enter image description here

Now Bash sees the second redirect, >file, and it redirects stdout to file:

Enter image description here

Do you see what happens here? Stdout now points to file, but the stderr still points to the terminal! Everything that gets written to stderr still gets printed out to the screen! So be very, very careful with the order of redirects!

Also note that in Bash, writing

$ command &>file

is exactly the same as:

$ command >&file

Solution 5

The numbers refer to the file descriptors (fd).

  • Zero is stdin
  • One is stdout
  • Two is stderr

2>&1 redirects fd 2 to 1.

This works for any number of file descriptors if the program uses them.

You can look at /usr/include/unistd.h if you forget them:

/* Standard file descriptors.  */
#define STDIN_FILENO    0   /* Standard input.  */
#define STDOUT_FILENO   1   /* Standard output.  */
#define STDERR_FILENO   2   /* Standard error output.  */

That said I have written C tools that use non-standard file descriptors for custom logging so you don't see it unless you redirect it to a file or something.

Share:
1,409,419
Tristan Havelick
Author by

Tristan Havelick

I'm a full-stack web software engineer My professional work currently centers around Python/React/PHP but in the past I've done a lot of Ruby and ASP/ASP.Net/C# stuff. I know a little of a ton of languages, and I'm currently honing managerial skills as well as getting better with front end tech.

Updated on January 19, 2022

Comments

  • Tristan Havelick
    Tristan Havelick over 2 years

    In a Unix shell, if I want to combine stderr and stdout into the stdout stream for further manipulation, I can append the following on the end of my command:

    2>&1
    

    So, if I want to use head on the output from g++, I can do something like this:

    g++ lots_of_errors 2>&1 | head
    

    so I can see only the first few errors.

    I always have trouble remembering this, and I constantly have to go look it up, and it is mainly because I don't fully understand the syntax of this particular trick.

    Can someone break this up and explain character by character what 2>&1 means?

  • Michael Cramer
    Michael Cramer almost 15 years
    Although that last example would be much clearer as: foo >outfile2 2>outfile1
  • paxdiablo
    paxdiablo almost 15 years
    Clearer, yes, but that wouldn't show the "positional" nature of redirection. The example is contrived since it's not usually useful to do this in a single line - the method becomes really useful when different parties are responsible for the different parts of the redirection. For example, when a script does one bit of redirection and you run it with another bit.
  • Thang Pham
    Thang Pham almost 13 years
    does this make any sense to you, java ... 2&1 >> data.log, I saw one of my colleague did this?
  • Thang Pham
    Thang Pham almost 13 years
    does this make any sense to you, java... 2&1 >> data.log, I saw one of my colleague did this?
  • dbr
    dbr almost 13 years
    @Harry that looks like either a shell that isn't bash, or a typo.. cmd 2>&1 >> somefile.log will append stdout/stderr to a file - it's basically the same as above, with >> file to append
  • Khue Vu
    Khue Vu over 12 years
    >> means append the output to the data.log file.
  • snapfractalpop
    snapfractalpop over 11 years
    I just realized that the last example also resolves a long standing confusion I had regarding why this: some_program 2>&1 > /dev/null does not work like this: some_program > /dev/null 2>&1.
  • F. Hauri  - Give Up GitHub
    F. Hauri - Give Up GitHub over 11 years
    @ThangPham mean STDOUT appended to data.log and STDERR dumped to STDOUT (console or next command) see my answer
  • Bad Request
    Bad Request almost 11 years
    This looks accurate to me. How is it 'not entirely accurate'?
  • William Pursell
    William Pursell almost 11 years
    @dbr cmd 2>&1 >>file does not redirect stderr to the file, but cmd >> file 2>&1 does. Order matters. In the first case, stderr is redirected to the stdout of the shell (possibly a tty if the command is entered interactively), and then stdout is directed to the file. In the second case, stdout is directed to the file, and then stderr is directed to the same place.
  • dokaspar
    dokaspar over 10 years
    but then shouldn't it rather be &2>&1?
  • F. Hauri  - Give Up GitHub
    F. Hauri - Give Up GitHub over 10 years
    Further reading: If you liked this, you may apreciate: How redirection abuse could give strange behaviours
  • Adam Rosenfield
    Adam Rosenfield over 10 years
    @Dominik: Nope, & is only interpreted to mean "file descriptor" in the context of redirections. Writing command &2>& is parsed as command & and 2>&1, i.e. "run command in the background, then run the command 2 and redirect its stdout into its stdout".
  • CommaToast
    CommaToast almost 10 years
    Why did they pick such arcane stuff as this? Just curious.
  • Martín Fixman
    Martín Fixman over 9 years
    But how would you redirect stderr to a file named '&1'?
  • F. Hauri  - Give Up GitHub
    F. Hauri - Give Up GitHub over 9 years
  • F. Hauri  - Give Up GitHub
    F. Hauri - Give Up GitHub about 9 years
    The second sample is wrong: as order precedence STDERR is redirected to STDOUT, only default STDOUT will be written to debug.log (not STDERR) see my answer (the paragraph #2)! To ensure both to be redirected to same file, you have to invert redirections directives: perl test.pl > debug.log 2>&1
  • Max West
    Max West about 9 years
    I like the answer above, but it could be a touch clearer. "2>&1" redirects stderr to the target of stdout. So if you have something like "ls -l >> directoryContents 2>&1" The result will be a file named directoryContents will have the contents of the working directory appended to it. If there are any errors in execution: the error messages will also be appended to the directoryContents file, as they occur.
  • Admin
    Admin about 8 years
    @Martin: 2>'&1'
  • M.M
    M.M over 7 years
    The last two are different if "command" ends in a number, as then that is taken as optional file descriptor for >&
  • JonnyRaa
    JonnyRaa over 6 years
    any idea why this interacts with grep highlighting? nginx -V 2>&1 | grep auth_request, highlights the word auth_request in red but nginx -V | grep auth_request doesn't
  • bakalolo
    bakalolo over 6 years
    so & meanings file descriptor and also go to the background?? Linux needs to stop using the same symbol too confusing!!
  • Nils-o-mat
    Nils-o-mat about 6 years
    Your comment about the last example is worth its letters in gold :-) I never thought that these redirectional arguments are positional... I think this is pretty important to know.
  • lindes
    lindes almost 6 years
    In case this helps for mnemonics for someone, the way I think of this connects with the C-language & operator, "address of" -- so, 2>&1 as a whole I read in my head as something resembling "(file descriptor) 2 redirects to the address of (file descriptor) 1". I.e. to where fd1 is currently going, as of the time the shell reads that 4-character sequence. (Because it can change. For fun, try: ((echo 1/stdout; echo 2/stderr >&2) 2>&1 > /dev/tty) | grep --color . -- it'll colorize what started out as standard error ("2/stderr").)
  • Cloud
    Cloud almost 6 years
    Is 0(or 1,2)>&0(or 1,2) like an option to control the output? Is echo test >test.log 2>&1 same as echo test 2>&1 >test.log?
  • radiantshaw
    radiantshaw over 5 years
    What happens if I do 2> &1 (space after >) instead of 2>&1? I'm not trying it out myself over the fear of breaking stuff.
  • Beejor
    Beejor almost 5 years
    @radiantshaw It just gives an error message. In bash: foo 2>&1 outputs "-bash: foo: command not found", and foo 2> &1 outputs "-bash: syntax error near unexpected token '&'". Shells are often picky about whitespace around symbols. @Aaron Franke Yes, foo 2>\&1 creates a new file named "&1", containing the above error text.
  • HCSF
    HCSF almost 5 years
    Very nice drawing and explanation! Could you elaborate what "duplicate" really means? You mentioned, "This one [2>&1] duplicates file descriptor 2 to be a copy of file descriptor 1". It sounds like stderr gets duplicated to stdout. But if it is the case, should I also see err though /dev/tty0?
  • Fakher Mokadem
    Fakher Mokadem over 4 years
    why did you say it's not entirely accurate? What detail did you jump over?
  • ikegami
    ikegami almost 4 years
    Re "Why did they pick such arcane stuff as this?", It's actually good to use related tokens for related things. In bash, < redirects from a file; <& redirects from a fd; <<... redirects from a here-doc, <(...) redirects from a process; and <<< ... redirects from a string literal.
  • JustAMartin
    JustAMartin over 3 years
    @CommaToast Exactly. Everybody is telling me "Magic constants are bad in programming, avoid them, use names instead". And we have hard-coded file descriptor integers in the core of an operating system. Yack. Why couldn't they just use keywords like stderr > stdout? Another inconsistency - > usually means "replace". So, 2>&1 can be confused with replacing all output with error output. Why not use >> for appending, as we do for files? So, I vote for stderr >> stdout.
  • user3932000
    user3932000 over 3 years
    @CommaToast You could say the same about just about any shell operations. Arcane symbols, overloaded operators, one-letter flags...
  • MaXi32
    MaXi32 over 3 years
    This is a very nice explanation with visual. If I became the one who ask this question, I will mark this as accepted answer.
  • xmar
    xmar over 3 years
    As a mnemonic, if you know C, following pointer arithmetics, you can think of it as "contents of 2 (2) go (>) to where 1 is, i.e. to the memory address of 1 (&1)".
  • gardenapple
    gardenapple over 2 years
    Is it okay to just use your own "non-standard file descriptors"? How do you know there isn't an open file with the same FD?
  • F. Hauri  - Give Up GitHub
    F. Hauri - Give Up GitHub over 2 years
    @fabs If you liked this, maybe would you like Open new window for input/output and/or Redirections from script himself
  • Shiva
    Shiva about 2 years
    +1 for "&1 is used to reference the value of the file descriptor 1 (stdout).". I always wondered why it wasn't just 2>1
  • T - Gott
    T - Gott about 2 years
    @JustAMartin you can use 2>> /dev/stdout instead of 2>&1. I don't think there is a way to replace the 2>> with a keyword though since it would not be distinguishable from an argument to the command. You should use >> now because in this case the output file will be opened again instead of just duplicating the file descriptor, and > truncates the file after opening (which you don't want if stdout is redirected to a log file).
  • huangzonghao
    huangzonghao about 2 years
    lol I have been suffered for years that there was this mysterious 1 file on my working directory and couldn't find it anywhere in the documentation of the command that I thought created this file. And thank god you let me realized that this file has always been created by the bash wrapper I wrote, where I used this great 2>1 in a command for logging.