Computer Science Atlas
Code Review

Bash Examples: Redirect stdout and stderr

February 4, 2021|Last Updated April 16, 2021
 

stdout 1 and stderr 2

On Linux and other Unix-like / POSIX operating systems, the two standard streams to which programs can send output are:

In addition to their names, you can also refer to these streams by their POSIX file descriptor numbers:

Normally when you run a program in a terminal window, both stdout and stderr output show up on screen.

Redirect to File

But what if you would rather save the output to a file? Bash (along with other shells) provides a redirect operator > to change where the output gets sent. The syntax looks like:

Bash
Copy
[source] > [destination]
$
[source] > [destination]

You can also leave out the spaces:

Bash
Copy
[source]>[destination]
$
[source]>[destination]

Now let's take a look at some examples of the operator in action. In the examples, we'll assume that you want to redirect the output of a program called cmd to files on disk (out.log and/or err.log).

Bash
Copy
cmd 1>out.log            # Redirect stdout to out.log
cmd >out.log             # Same as above (1 = stdout is implied)
cmd > out.log            # Same as above (spaces don't matter)
cmd 2>err.log            # Redirect stderr to file err.log
cmd 1>out.log 2>err.log  # Redirect stdout to file out.log, \
                         #          stderr to err.log
$
$
$
$
$

cmd 1>out.log            # Redirect stdout to out.log
cmd >out.log             # Same as above (1 = stdout is implied)
cmd > out.log            # Same as above (spaces don't matter)
cmd 2>err.log            # Redirect stderr to file err.log
cmd 1>out.log 2>err.log  # Redirect stdout to file out.log, \
                         #          stderr to err.log

If you want to send output to multiple destinations, such as both to a file and the terminal screen simultaneously, you won't be able to accomplish that using > — instead, you'll need to enlist the help of a utility called tee.

Combining Output

Notice in the last line of the examples above, you're redirecting stdout and stderr to different files. In this case, the filenames must be different (>out.log 2>out.log does not work).

To combine their output and redirect to a single file, you have to use the reference operator & followed by the number of the file you want (i.e., &1 for stdout, &2 for stderr). Below are some examples.

Bash
Copy
cmd 2>&1                 # Redirect stderr to stdout
cmd 1>&2                 # Redirect stdout to stderr
cmd 1>combined.log 2>&1  # Redirect stdout and stderr to file combined.log
$
$
$
cmd 2>&1                 # Redirect stderr to stdout
cmd 1>&2                 # Redirect stdout to stderr
cmd 1>combined.log 2>&1  # Redirect stdout and stderr to file combined.log

In the last line, >combined.log sends stdout to file combined.log, and 2>&1 sends stderr to stdout, resulting in everything going to file combined.log.

Silence Output: /dev/null

On Linux and many other systems, you can also redirect output to a special file called /dev/null ("null device") which takes output but doesn't send it anywhere. It provides a way to hide output from a program on screen, but also not save it to any file on disk.

Bash
Copy
cmd 1>/dev/null       # Silence stdout
cmd > /dev/null       # Same as above (1 is implied)
cmd 2>/dev/null       # Silence stderr
cmd 1>/dev/null 2>&1  # Silence both stdout and stderr
cmd > /dev/null 2>&1  # Same as above (1 is implied)
$
$
$
$
$
cmd 1>/dev/null       # Silence stdout
cmd > /dev/null       # Same as above (1 is implied)
cmd 2>/dev/null       # Silence stderr
cmd 1>/dev/null 2>&1  # Silence both stdout and stderr
cmd > /dev/null 2>&1  # Same as above (1 is implied)

Order Matters

Note that the left-to-right order of redirections matters. The command:

Bash
Copy
cmd > /dev/null 2>&1
$
cmd > /dev/null 2>&1

does two things in this order:

  1. > /dev/null: redirects stdout to /dev/null; and then
  2. 2>&1: redirects stderr to whereever stdout is going, which is now /dev/null.

As a result, you will not see any output (i.e., both stdout and stderr are silenced).

However this command:

Bash
Copy
cmd 2>&1 > /dev/null
$
cmd 2>&1 > /dev/null

does two things in this order:

  1. 2>&1: redirects stderr to whereever stdout is going, which currently is just the terminal output; and then
  2. > /dev/null: redirects stdout to /dev/null. stderr is not changed, and will still send output to the terminal.

As a result, this command will display stderr output, but not stdout.

References

See Also