Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Since this is hackernews, can someone explain the rational behind putting the 2>&1 after the > ?

I know it works, but this reads to me: command > file.txt 2>&1 "write the output of command to file.txt and then map the error output to stdout"

It makes so much more sense to write: command 2>&1 > file.txt

There is clearly something in my brain that is confused about how redirection works.



&1 refers to file descriptor 1. a>&b calls dup2(2) with oldfd=b and newfd=a. So ordering matters. STDOUT starts out attached to fd=1, but if you dup something else to fd=1, the association "fd 1 is STDOUT" is forgotten.

And that's exactly what usually happens; we replace fd 1 with one open to /dev/null, and then when we say 2>&1, that means to replace fd 2 (stderr) with whatever's at fd 1 (now /dev/null). When you write "command 2>&1 >/dev/null" that means something else, it means "send fd 2's output to what's currently at fd 1 (stdout)", and then "send what's currently at fd 1 to /dev/null". In other words, the source of a redirection is "by reference", but the destination of a redirection is "by value". If that makes any sense...


Think of it as saying "take fd 2 (stderr) and send it to the same place fd 1 is going now" So:

  $ command >file.txt 2>&1
first redirects fd=1 to file.txt and then has fd=2 go the same place. Where:

  $ command 2>&1 >file.txt
first has fd=2 go the original place stdout was and then redirect fd=1 only to file.txt. Usually not what you want. If you really wanted file.txt to get only the stdout while simultaneously sending what used to be stderr to stdout I think you'd have to use another file descriptor like:

  $ command 3>&1 >file.txt 2>&3
That is, save the original stdout as fd=3, redirect stdout, then make stderr go the same place fd=3 is going.


I think this[1] is probably what you're looking for. If I'm understainding you correctly, the 2nd example will have mapped 2/stderr to &1 (stdout), before pointing stdout to the file, so you end up with both in the file.

[1] http://wiki.bash-hackers.org/syntax/redirection#multiple_red...


Siblings have already responded to this well, so I'll just add an example:

  $ ls x
  ls: cannot access x: No such file or directory
  $ ls x >/dev/null 2>&1
  $ ls x 2>&1 >/dev/null
  ls: cannot access x: No such file or directory
The first command shows us trying to list a non-existent file, raising an error. The second sends stderr to stdout before sending stdout to null, suppressing all output. The third sends the error to stdout; any output on stdout would have been suppressed (can you come up with a way to verify this?)


can you come up with a way to verify this?

   perl -E 'say q{STDOUT!}; say {*STDERR} q{STDERR!}'
(q{...} quoting to avoid ugliness of quotes inside quotes.)


Your second example puts stderr into the old stdout, then makes a new stdout go into the file. You have to redirect the files in the proper sequence to get the desired behavior. It is quirky if you don't expect it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: