IO Redirection - Swapping stdout and stderr

Richard picture Richard · Nov 8, 2012 · Viewed 9.2k times · Source

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!

Answer

unbeli picture unbeli · Nov 8, 2012
% (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).