Search code examples
bashshellio-redirection

How do these stream redirections work?


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?


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.