Chris F.A. Johnson
Unix shell programming notes

24 August 2004

Redirecting stdout and stderr

By default, each Unix process has 3 file descriptors (FDs) assigned to it, 0, 1 and 2; these are known as stdin, stdout, and stderr respectively. They are normally connected to your terminal: stdin is the keyboard; stdout and stderr are your screen.

Each of these represents a stream that can be redirected to other places, such as files or pipes. The output streams, stdout and stderr can be combined and sent to the same place, or directed to different locations.

If you redirect stdout (FD1) to a file, stderr (FD2) will still go to your screen.

$ ls -ld /home /qwerty
ls: /qwerty: No such file or directory
drwxr-xr-x  11 root root 4096 Jul 11 02:58 /home

If we redirect stdout to the bit bucket, the stderr will still be sent to the screen:

$ ls -ld /home /qwerty 1>/dev/null
ls: /qwerty: No such file or directory

(NOTE: the 1 can be left off; >xxxx implies 1>xxxx.)

Similarly, if we redirect stderr to the bit bucket, the stdout will still be sent to the screen:

$ ls -ld /home /qwerty 2>/dev/null
drwxr-xr-x  11 root root 4096 Jul 11 02:58 /home

Or we can redirect both stderr and stdout to the bit bucket:

$ ls -ld /home /qwerty >/dev/null 2>/dev/null

This works with /dev/null, which isn't a real file, but redirecting both stdout and stderr to the same file individually will not work, as both redirections truncate the file:

$ ls -ld /home /qwerty >/tmp/xxx 2>/tmp/xxx

(The full explanation is too technical for this tip, but it is akin to redirecting output to the same file as the input.)

To redirect both stdout and stderr to the same file, we redirect one stream to the file, then redirect the other to the first stream:

$ ls -ld /home /qwerty >/tmp/xxx 2>&1

The order of the redirections is important. This will send stderr to the terminal and stdout to the file /tmp/xxx:

$ ls -ld /home /qwerty 2>&1 >/tmp/xxx

Sending stderr to stdout attaches the stream to wherever stdout is pointing at the time of the redirection. It is as if stdout and stderr are variables; you are doing the equivalent of:

## the defaults
stdout=screen
stderr=screen

## redirect stderr
stderr=$stdout

## redirect stdout
stdout=/dev/null

Now, stdout=/dev/null, and stderr=screen.

If you change the order, the result is different:

## the defaults
stdout=screen
stderr=screen

## redirect stdout
stdout=/dev/null

## redirect stderr
stderr=$stdout

Now, stdout and stderr are both pointing to /dev/null.

Modified 18 Nov 2021