Tuesday Tiny Techie Tip

Bourne Shell Redirection

Last week I talked about redirection in csh(1). At the end of the discussion I pointed out that there's no way to seperately redirect stderr and stdout, you either redirect stdout to a file and let stderr go, or redirect both stderr and stdout, but if you want to redirect just stderr, you're hosed.

Bourne shell makes this easy.

Bourne shell uses the single digit file descriptors that will be familiar to UNIX C programmers. By default, stdin is associated with fd0, stdout with fd1, stderr with fd2. The other digits are not assigned by default.

In order to redirect input or output, you create associations between file descriptors and files and between file descriptors and other file descriptors. To associate a file descriptor with a file, you do this:


1> file

This associates output to fd1 with the file "file". Since stdout is already writing to fd1 by default, this effectively redirects stdout to "file". As in csh, a double angle bracket indicates that writes should be appended to the file rather than having the file initially truncated.

To associate one file descriptor with another, you do this:


2>&1

This says to send anything written to fd2 to the same place as output to fd1. Since fd1 is stdout, and fd2 is stderr, this says to send stderr to the same place as stdout. The underlying mechanism is the dup2(2) system call.

So let's look at how to do various kinds of redirection:

Redirect stdout to a file

$ ls 1> file
$ ls > file

Since the default file descriptor for output redirection is fd1, the first form can be abbreviated to the second which is just like csh

Redirect stdin from a file

$ wc 0< file
$ wc < file

Since the default file descriptor for input redirection is fd0, the first form can be abbreviated to the second which is just like csh

Redirect stdin from text

$ wc << END
This is some text
that will be counted
by wc(1).
END

Just like csh

Redirect stderr to a file

$ ls 2> file

This redirects just stderr output (associated with fd2) to the file. stdout is unchanged. Can't be done in csh.

Redirect both stdout and stderr to a file

$ ls > file 2>&1

First the "> file" indicates that stdout should be sent to the file, then the "2>&1" indicates that stderr (fd2) should be sent to the same place as stdout (fd1).

To append to the file, only the stdout redirection must change since stderr is just hitching a lift on whatever stdout is doing.


$ ls >> file 2>&1

Redirect stdout to one file and stderr to another

$ ls > file 2> file2

Try doing that in csh! (Actually, it can be done, but you have to spawn a subshell)

Pipe one process' stdout to another's stdin

$ ls | wc

Just like csh, but note that there is no analog to the csh "|&". See below for how to accomplish the same thing in Bourne shell.

Pipe one process' stdout and stderr to another's stdin

$ ls 2>&1 | wc

Here we combine stderr onto the stdout stream, then use "|" to pipe the result to the next process.

Combinations

$ sed 's/^#//' < file 2> sederr | \
	wc -l 2> wcerr | \
	awk '{print $NF}' > final 2> awkerr

Here I'm saving the error output from each command in the pipeline to a separate file ("sederr", "wcerr", "awkerr"), but letting stdout go straight through the pipe into the file "final". Input to sed(1) at the beginning of the pipe is redirected from the file "file"


Tuesday Tiny Techie Tip -- 15 April 1997
Forward to (04/22/97)
Back to (04/08/97)
Written by Jeff Youngstrom

Up to the TTTT index

Tuesday Tiny Techie Tips are all © Copyright 1996-1997 by Jeff Youngstrom. Please ask permission before reproducing any of this material.