RSS Feed Share on Twitter

All Shell Scripting Tips

25 April 2019

Redirecting Standard Output and Errors

Redirecting Standard Output (stdout) and Standard Error (stderr) streams

When a shell is created it opens three files, each having an integer file descriptor.

0: Standard Input (stdin) – this is normally a keyboard
1: Standard Output (stdout) – this is typically your terminal emulator
2: Standard Error (stderr) – this is normally the same as Standard Output, but it is possible to redirect errors to a different place. This can be useful for hiding unnecessary error messages, or for saving a log of errors, and many other reasons.

The short script below (called "testme") writes a message to standard output, then another (slightly different) message to standard error. This script uses three shell idioms:
     1) The $@ variable is special, in that it contains all of the arguments passed to the script. We will use this later to show how the shell has parsed the command-line.
     2) Because the entire message is in double quotes, to get the output to display some double quotes around the list of parameters, we need to use \" to mark the " symbol as being a character to display, rather than treating it as the end of the quoted message.
     3) The final line sends its output to stderr (rather than stdout) by redirecting to file descriptor 2, which as we saw above, is stderr. It does this with the ">&2" syntax.

The script is as follows. This is enough to be able to accurately test what happens in different situations: How the Standard and Error streams are redirected, and how the parameters to the script are parsed.

download the "testme" script

$ cat testme
#!/bin/bash
echo "This is Standard Output (stdout) and my parameters are \"$@\""
echo "This is Standard Error (stderr) and my parameters are \"$@\"" >&2

When we run this script, it writes output and errors to the same place. It also tells us what parameters it was called with:

$ ./testme hello world
This is Standard Output (stdout) and my parameters are "hello world"
This is Standard Error (stderr) and my parameters are "hello world"
$

We can hide the regular (stdout) output, but still show errors, by redirecting stdout (the default stream) to the special "/dev/null" device. "/dev/null" simply reads anything passed to it, and discards them.

$ ./testme hello world > /dev/null
This is Standard Error (stderr) and my parameters are "hello world"
$

We can also choose just to hide the errors, but keep the standard output. Because stderr is file descriptor 2, we say "2> /dev/null":

$ ./testme hello world 2> /dev/null
This is Standard Output (stdout) and my parameters are "hello world"
$

Be careful here, because whitespace matters. If we put "2 > /dev/null" instead of "2> /dev/null", then the shell interprets your command as being "testme hello world 2" and that you want the stdout (not stderr) to be sent to /dev/null. If you think about it, how else would you be able to pass "hello world 2" and tell the shell to redirect stdout?

$ ./testme hello world 2 > /dev/null
This is Standard Error (stderr) and my parameters are "hello world 2"
$

Redirecting Stdout and Stderr Together

We can also redirect both stdout and stderr to /dev/null. Now nothing is displayed at all:

$ ./testme hello world > /dev/null 2>/dev/null
$

There is also another way to say "and send stderr to wherever stdout is going" by referring to stdout as "&1"; the shell will substitute this with /dev/null, since that is where stdout is going:

$ ./testme hello world > /dev/null 2>&1
$

Again, spaces matter. The entire "2>&1" must have no whitespace at all, otherwise strange things happen:

$ ./testme hello world > /dev/null 2 > &1
bash: syntax error near unexpected token `&'
$

And again, because the "> /dev/null" syntax is interpreted by the shell, if you apply the spacing like this, your stdout will be redirected (twice, as it happens) to /dev/null, the "2" is treated as a parameter to the script itself, and stderr is not redirected at all:

$ ./testme hello world > /dev/null 2 > /dev/null
This is Standard Error (stderr) and my parameters are "hello world 2"
$

Redirecting Elsewhere

Of course, you don't have to send everything to /dev/null. You can redirect to a file, like this example, which sends stdout to /tmp/hello.txt. Note that stderr is still displayed to your terminal.

$ ./testme hello world > /tmp/hello.txt
This is Standard Error (stderr) and my parameters are "hello world"
$ cat /tmp/hello.txt
This is Standard Output (stdout) and my parameters are "hello world"
$

Similarly, you can send stdout to /tmp/hello.txt, and any errors to /tmp/error.log for reference:

$ ./testme hello world > /tmp/hello.txt 2> /tmp/error.log
$ cat /tmp/hello.txt
This is Standard Output (stdout) and my parameters are "hello world"
$ cat /tmp/error.log
This is Standard Error (stderr) and my parameters are "hello world"
$ 

Conclusion

You can redirect to any given file descriptor, by its integer representation, via the ">&2" syntax, as shown in the "testme" script itself. You can then redirect those streams to wherever you like via the "> /dev/null" or "2> /dev/null" syntax, according to the output you want to redirect. The default is file descriptor 1 (stdout).

 

 

 

 


You can buy the content of this tutorial as a PDF to download to all of your devices!

Contact

You can mail me with this form. If you expect a reply, please ensure that the address you specify is valid. Don't forget to include the simple addition question at the end of the form, to prove that you are a real person!