snickerdoodles777
snickerdoodles777

Reputation: 685

What's the difference between `command > output` and `command 2>&1 > output`?

I'm somewhat familiar with the common way of redirecting stdout to a file, and then redirecting stderr to stdout. If I run a command such as ls > output.txt 2>&1, my guess is that under the hood, the shell is executing something like the following c code:

close(1)
open("output.txt") // assigned to fd 1
close(2)
dup2(1, 2)

Since fd 1 has already been replaced with output.txt, anything printed to stderr will be redirected to output.txt. But, if I run ls 2>&1 > output.txt, I'm guessing that this is instead what happens:

close(2)
dup2(1, 2)
close(1)
open("output.txt")

But, since the shell prints out both stdout and stderr by default, is there any difference between ls 2>&1 output.txt and ls > output.txt? In both cases, stdout will be redirected to output.txt, while stderr will be printed to the console.

Upvotes: 1

Views: 156

Answers (1)

Scott McPeak
Scott McPeak

Reputation: 12739

With ls >output.txt, the stderr from ls goes to the stderr inherited from the calling process. In contrast, with ls 2>&1 >output.txt, the stderr of ls is sent to the stdout of the calling process.

Let's try this with an example script that prints a line of output to each of stdout and stderr:

$ cat pr.sh
#!/bin/sh
echo "to stdout"
echo "to stderr" 1>&2

$ sh pr.sh >/dev/null
to stderr

$ sh pr.sh 2>/dev/null
to stdout

Now if we insert "2>&1" into the first command line, nothing appears different:

$ sh pr.sh 2>&1 >/dev/null
to stderr

But now let's run both of those inside a context where the inherited stdout is going someplace other than the console:

$ (sh pr.sh 2>&1 >/dev/null) >/dev/null

$ (sh pr.sh      >/dev/null) >/dev/null
to stderr

The second command still prints because the inherited stderr is still going to the console. But the first prints nothing because the "2>&1" redirects the inner stderr to the outer stdout, which is going to /dev/null.

Although I've never used this construction, conceivably it could be useful in a situation where (in a script, most likely) you want to run a program, send its stdout to a file, but forward its stderr on to the caller as if it were "normal" output, perhaps because that program is being run along with some other programs and you want the first program's "error" output to be part of the same stream as the other programs' "normal" output. (Perhaps both programs are compilers, and you want to capture all the error messages, but they disagree about which stream errors are sent to.)

Upvotes: 2

Related Questions