Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IO Redirection - Swapping stdout and stderr

Given a shell script:

#!/bin/sh  echo "I'm stdout"; echo "I'm stderr" >&2; 

Is there a way to call that script such that only stderr would print out, when the last part of the command is 2>/dev/null, ie

$ > sh myscript.sh SOME_OPTIONS_HERE 2>/dev/null I'm stderr 

Or, alternatively:

$ > sh myscript.sh SOME_OPTIONS_HERE >/dev/null I'm stdout 

It's a question at the end of a set of lecture slides, but after nearly a day working at this, I'm nearly certain it's some sort of typo. Pivoting doesn't work. 2>&- doesn't work. I'm out of ideas!

like image 534
Richard Avatar asked Nov 08 '12 22:11

Richard


People also ask

Which is used to redirect both stdout and stderr?

Understanding the concept of redirections and file descriptors is very important when working on the command line. To redirect stderr and stdout , use the 2>&1 or &> constructs.

What is the meaning of 2 >& 1?

The 1 denotes standard output (stdout). The 2 denotes standard error (stderr). So 2>&1 says to send standard error to where ever standard output is being redirected as well.

What is redirecting stderr to stdout?

The regular output is sent to Standard Out (STDOUT) and the error messages are sent to Standard Error (STDERR). When you redirect console output using the > symbol, you are only redirecting STDOUT. In order to redirect STDERR, you have to specify 2> for the redirection symbol.

What is the difference between stdout and stderr?

stdout − It stands for standard output, and is used to text output of any command you type in the terminal, and then that output is stored in the stdout stream. stderr − It stands for standard error. It is invoked whenever a command faces an error, then that error message gets stored in this data stream.


2 Answers

% (sh myscript.sh 3>&2 2>&1 1>&3) 2>/dev/null I'm stderr % (sh myscript.sh 3>&2 2>&1 1>&3) >/dev/null  I'm stdout 

Explanation of 3>&2 2>&1 1>&3:

  • 3>&2 means make a copy of file descriptor 2 (fd 2) (stderr), named fd 3 (file descriptor 3). It copies the file descriptor, it doesn't duplicate the stream as tee does.
  • 2>&1 means that fd 2 of sh myscript.sh becomes a copy of it's fd 1 (stdout). Now, when myscript writes to it's stderr (it's fd 2), we receive it on stdout (our fd 1).
  • 1>&3 means that fd 1 of sh myscript.sh becomes a copy of fd 3 (stderr). Now, when myscript writes to it's stdout (it's fd 1), we receive it on stderr (our fd 2).
like image 68
unbeli Avatar answered Oct 01 '22 09:10

unbeli


For sake of completeness, based on a comment by @200_success above, it is probably better to move the file descriptor 3 using 1>&3- :

$ (sh myscript.sh 3>&2 2>&1 1>&3-) 2>/dev/null I'm stderr $ (sh myscript.sh 3>&2 2>&1 1>&3-) >/dev/null  I'm stdout 

Instead of swapping file descriptors on a per-process basis, using exec you can swap stdin & stderr for all following commands launched by the current shell :

$ (exec 3>&2 2>&1 1>&3- ; sh myscript.sh ; sh myscript.sh ) 2>/dev/null I'm stderr I'm stderr $ (exec 3>&2 2>&1 1>&3- ; sh myscript.sh ; sh myscript.sh ) >/dev/null  I'm stdout I'm stdout 
like image 33
Sylvain Leroux Avatar answered Oct 01 '22 09:10

Sylvain Leroux