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!
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.
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.
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.
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.
% (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).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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With