Redirection and Pipes
Steven Zeil
One of the interesting ideas that pervades Unix is that many, if not most, programs can be viewed as “filters” or “transforms” that take a stream of text as input and produce an altered stream of text as output. Many Unix commands are designed to perform relatively trivial tasks, perhaps not very useful by themselves, that can be chained together in interesting and useful ways.
The practical consequence of this is that Unix shells devote special attention to a standard input stream that forms the main input to most programs/commands, and to a standard output stream that forms the main output from most programs/commands.
The shell attempts to make it easy either to redirect one of these standard streams to a file or to pipe the standard output stream of one program into the standard input of another.
1 Redirection
1.1 Input Redirection
Input redirection sends text from a file to the standard input of a program as if it were being typed from the keyboard.
1.1.1 Example: wc
For example, the program wc
(for word count) reads text from its input stream and produces as its output stream three numbers indicating the number of lines, words, and characters that it saw. You could invoke this directly:
wc
Hello.
How are you?
^D
in which case, you would see as output:
2 4 20
For this to be very useful, however, we need to make it accept a file as input. We can do this using the <
operator in the shell. Think of the <
as an arrow indicating data flowing towards the command from a filename: If hello.c
is this file:
#include <stdio.h>
int main ()
{
printf ("Hello from C!\n");
return 0;
}
then the command
wc < hello.c
produces the output
6 13 80
You can also focus the wc
command on characters, lines, or words with options -c
, -w
, or -l
, respectively. For example,
wc -l < hello.c
produces the output
6
1.2 Output Redirection
On the output end, the shell operator >
redirects the standard output into a file (again, think of this as an arrow indicating data flowing into a filename from the command):
wc < hello.c > hello.wc
produces no output on the screen, but creates a file called hello.wc
. That file will contain the output
6 13 80
of the wc
command.
Example 1: Try This:cd ~/playing echo Hello > greeting.txt more greeting.txt echo Goodbye > greeting.txt more greeting.txt echo Farewell > greeting.txt more greeting.txt
1.2.1 sed
Another command that is often used as a “filter” is sed
, the “Stream EDitor”. sed
allows you to enter a variety of editing commands that will be applied to every line of a stream of text coming from the standard in (or from a file).
The most common use of sed
is to scan each line of input for a pattern and to replace that pattern, wherever it occurs, by some string. The sed
command to do this is
sed s/pattern/replacement/g
where pattern describes the text to search for in each line, and replacement is the text we want to ue to replace the text matching the pattern.
(The ‘/’ characters are simply necessary to indicate the beginning and end of the pattern and replacement strings. They can be replaced by nearly any character that does not appear in either the pattern or replacement strings.)
There’s a lot of things that we can use to make elaborate search patterns and replacement strings, and we will cover those in a later lesson. For now, though, we will limit patterns to alphanumeric strings.
Example 2: Try This: Substitutions with sedcd ~/playing cp ~cs252/Assignments/ftpAsst/alas.txt . more alas.txt
Now try operating on that file with
sed
:sed s/o/X/g < alas.txt
The file
alas.txt
is presented tosed
as input because of the input redirection operator ‘<’.
sed
will actually accept input either at its standard in or as a named file name, sosed s/o/X/g alas.txt
without the redirection, will actually produce the same output.
The ‘g’ at the end of each of the prior
sed
command indicates that the change should be applied every time a match is found (i.e., this is a global replacement). If the ‘g’ is dropped, only the first match in each line will be replaced.Try the command
sed s/o/X/ < alas.txt
to see the effect of dropping the ‘g’.
Neither the pattern nor the replacement are limited to single letters.
Try:
sed 's!I!you!g' < alas.txt sed 's@Horatio@George@g' alas.txt
By default,
sed
is case-sensitive. You can add an ‘i’ flag at the end of the substitution to change this. Compare the outputs of these commands:sed 's/I/you/g' < alas.txt sed 's/I/you/gi' < alas.txt
1.3 Combining Input and Output Redirection
A command can use both input and output redirection, but it is crucial that different files be used for the input and the output.
Example 3: Try This: Dual Redirectioncd ~/playing echo Hello > greeting.txt sed s/el/o/ < greeting.txt > holo.txt more greeting.txt more holo.txt sed s/el/o/ < greeting.txt > greeting.txt more greeting.txt
The first
sed
command rewrites the contents of the input file, saving the rewritten content in the output file.The second
sed
command trashes the input file contents. That’s because the first step in preparing a file for output is to empty out any prior contents, and that is done by the command shell program that interprets your keyboard command and launches thesed
program. So the file gets emptied out before thesed
command is actually launched.sed
never gets a chance to read the input file’s contents.
1.4 Appending to Files
The output redirection operator has an important variant. Sometimes we would like to add output to the end of an existing file instead of replacing that file. This is done with the operator >>
. So the code sequence
wc < hello.c > hello.wc
wc < hello.c >> hello.wc
would result in a file hello.wc
with contents
6 13 80
6 13 80
regardless of whether hello.wc
had existed previously.
Example 4: Try This:cd ~/playing echo Aloha >> greeting.txt more greeting.txt
2 Pipes
Redirection uses files for input or output.
We can also send the output of a command to the input of another command. We envision this action as if we had connected the two commands by a pipe through which the output text of one command is flowing to the input of the other.
To pipe the output of one command into the input of another, use the shell operator |
. A common example of a pipe is to take a command that may have a large amount of output and to pipe it through more
to facilitate viewing.
Example 5: Try This:Try these commands:
ls /bin ls /bin | more
As you gain facility with a greater variety of Unix text manipulation commands, you will find that redirection and pipes can be a powerful combination. For example, suppose that you have written program myprog
that emits a great deal of output, among which might be some error messages starting with the phrase “ERROR:
”. If you wanted to read only the error messages, you could, of course, just view all the output, watching for the occasional error message:
myprog | more
But if the program produces a lot of output, this will quickly become tedious. However, we previously encountered the program grep
, which scans its input stream, printing only those lines matching a given regular expression. By piping the myprog
output through grep
, we can limit the output to the part we really want to see:
myprog | grep "ERROR:" | more
Example 6: Try This:You can use sed to reformat the output from some commands. Give the following commands:
cd ~/playing echo Hello > greeting.txt cat greeting.txt cat greeting.txt | sed -e 's/^/She said, "/' -e 's/o/o"./'
The -e option to sed allows us to string together multiple substitution commands.