Reputation: 94820
From this perldoc page,
To capture a command's STDERR and STDOUT together:
$output = `cmd 2>&1`;
To capture a command's STDOUT but discard its STDERR:
$output = `cmd 2>/dev/null`;
To capture a command's STDERR but discard its STDOUT (ordering is important here):
$output = `cmd 2>&1 1>/dev/null`;
To exchange a command's STDOUT and STDERR in order to capture the STDERR but leave its STDOUT to come out the old STDERR:
$output = `cmd 3>&1 1>&2 2>&3 3>&-`;
I do not understand how 3 and 4 work, and I am not too sure what I understand about 1 and 2 is right. Below is what I understand. Please correct me where I am wrong.
I know that 0
, 1
and 2
symbolize STDIN
, STDOUT
and STDERR
.
redirect 2 to 1, so that both of them use the same stream now (&
escaped 1
making sure that STDERR
does not get redirected to a file named 1
instead)
redirect 2 (STDERR) to null stream, so that it gets discarded
I do not understand this one. Shouldn't it be just
$output = `cmd 1>/dev/null`;
Also, if the aim is to get the STDERR
messages at STDOUT
, won't 1>/dev/null
redirect everything to /dev/null
?
What is happening here? What is stream 3
? Is it like a temporary variable?
Upvotes: 5
Views: 1695
Reputation: 431
The redirections are evaluated from left to right. Here's a trace table:
cmd 3>&1 1>&2 2>&3 3>&-
1 (stdout) | 2 (stderr) | 3 | |
---|---|---|---|
1 | 2 | ||
3>&1 |
1 | 2 | 1 |
1>&2 |
2 | 2 | 1 |
2>&3 |
2 | 1* | 1 |
3>&- |
2 | 1 | - |
*Notice that file descriptor 2 points to 1, not 3. This is because it points to the file descriptor that 3 points to. Because of this, 2 isn't affected when 3 is closed in the next step
As you can see, a>&b
means "make a point to the thing b is currently pointing to"
Upvotes: 1
Reputation: 879471
Normally we have this:
1-->STDOUT
2-->STDERR
2>&1
redirects file descriptor fd2
to fd1
1-->STDOUT
/
2./
2>/dev/null
redirects fd2
to /dev/null
.
1-->STDOUT
2-->/dev/null
2>&1 1>/dev/null
redirects fd2
to fd1
, and then redirects fd1
to /dev/null
/dev/null
/
1./ STDOUT
/
2./
3>&1 1>&2 2>&3 3>&-
The whole thing effectively swaps fd1 and fd2. fd3 acted as a temporary variable.
1 --STDOUT
X
2 `-STDERR
See the docs for more information on IO redirection.
Upvotes: 4
Reputation: 27886
Though documented in the perldocs, the redirection is all standard linux redirection. You understand 1 and 2 correctly.
3) Only STDOUT is normally caught by a basic redirect (>
), so the original STDOUT must be discarded, and STDERR must be send to STDOUT.
4) cmd 3>&1 1>&2 2>&3 3>&-
is equivalent to
var tmp = STDOUT;
STDOUT = STDERR;
STDERR = tmp;
delete tmp;
Upvotes: 4
Reputation: 239861
Really, none of this is Perl -- all of this is handled by the shell that you're invoking by using the backticks operator. So your best reading is man sh
, or the Shell chapter of the Unix standard.
In short, though, for #4:
3>&1
: Open FD 3 to point to where stdout currently points.1>&2
: Reopen stdout to point to where stderr currently points.2>&3
: Reopen stderr to point to where FD 3 currently points, which is where stdout pointed before the previous step was completed. Now stdout and stderr have been succesfully swapped.3>&-
: Close FD 3 because it's not needed anymore.Upvotes: 4
Reputation: 798626
3.Nope. The ordering matters, so it gets rid of the original stdout, then it moves stderr to stdout.
4.3
is just another file descriptor, same as the first 3. Most processes can use a total of 256 different file descriptors.
Upvotes: -2