Question

From this perldoc page,

  1. To capture a command's STDERR and STDOUT together:

    $output = `cmd 2>&1`;
  2. To capture a command's STDOUT but discard its STDERR:

    $output = `cmd 2>/dev/null`;
  3. To capture a command's STDERR but discard its STDOUT (ordering is important here):

    $output = `cmd 2>&1 1>/dev/null`;
  4. 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.

  1. 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)

  2. redirect 2 (STDERR) to null stream, so that it gets discarded

  3. 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?

  4. What is happening here? What is stream 3? Is it like a temporary variable?

Was it helpful?

Solution

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.

OTHER TIPS

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;

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>&-

  1. first directs a new fd 3 to wherever fd 1 is currently pointing (STDOUT).
  2. then redirects fd1 to wherever fd2 is current pointing (STDERR),
  3. then redirects fd 2 to wherever fd 3 is currently pointing (STDOUT)
  4. then closes fd3 (3>&- means close file descriptor 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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top