< Zurück | Inhalt | Weiter >

1.3.1 Redirecting I/O

The second great accomplishment of UNIX,2 carried on into its Linux descen- dants, was the concept of redirecting input and output (I/O). It was based on the concept of a standardized way in which I/O would be done, called standard I/O.


1.3.1.1 Standard I/O

A familiar concept to Linux developers is the notion of standard I/O. Virtually every Linux process begins its life with three open file descriptors—standard in, standard out, and standard error. Standard in is the source of input for the process; standard out is the destination of the process’ output; and standard error is the destination for error messages. For “old fashioned” command-line applications, these correspond to keyboard input for standard in and the output window or screen for both standard out and error.

A feature of Linux that makes it so adaptable is its ability to redirect its I/O. Programs can be written generically to read from standard in and write to standard out, but then when the user runs the program, he or she can change (or redirect) the source (in) or destination (out) of the I/O. This allows a program to be used in different ways without changing its code.

Redirecting I/O is accomplished on the Linux shell command line by the “<” and “>” characters. Consider the ls program which lists the contents of a directory. Here is a sample run of ls:


$ ls

afile more.data zz.top

$


image

1. If you’re not using a windowing system, these commands are typed at the shell prompt that you get after you log in. But if you’re not using a windowing system, either you’re not a begin- ner (and don’t need this introduction) or you can’t get your windowing system to work, in which case you may need more help that we can give you here.

2. Yes, we are aware that much of UNIX actually comes from the Multics project, but we credit UNIX with popularizing it.


We can redirect its output to another location, a file, with the “>” character:


$ ls > my.files

$


The output from the ls command no longer appears on the screen (the default location of standard out); it has been redirected to the file my.files.

What makes this so powerful a construct (albeit for a very simple example) is the fact that not only was no change to the program required, but the pro- grammer who wrote the ls program also did nothing special for I/O. He simply built the program to write to standard out. The shell did the work of redirecting the output. This means that any program invoked by the shell can have its output similarly redirected.

Standard error is another location for output, but it was meant as the des- tination for error messages. For example, if you try to list the contents of a nonexistent directory, you get an error message:


$ ls bogus

ls: bogus: No such file or directory

$


If you redirect standard out, nothing changes:


$ ls bogus > save.out

ls: bogus: No such file or directory

$


That’s because the programmer wrote the program to send the message to standard error, not standard out. In the shell (bash) we can redirect standard error by preceding the redirect symbol with the number 2, as follows:3


$ ls bogus 2> save.out

$


image

3. The use of the number 2 comes from an implementation detail: All the I/O descriptors for a UNIX process were kept in an array. The first three elements of the array, numbered 0, 1, and 2, were defined to be the standard in, out, and err, in that order. Thus in the shell you can also redirect standard out by using “1>” as well as the shorter “>”.


Note there is no output visible from ls. The error message, ls: bogus: No such file or directory, has been written to the file save.out.

In a similar way standard input (stdin) can be redirected from its default source, the keyboard.

As an example, we’ll run the sort program. Unless you tell it otherwise, sort will read from stdin—that is, the keyboard. We type a short list of phrases and then type a ^D (a Control-D) which won’t really echo to the screen as we have shown but will tell Linux that it has reached the end of the input. The lines of text are then printed back out, now sorted by the first character of each line. (This is just the tip of the iceberg of what sort can do.)


$ sort

once upon a time a small creature came to live in the forest.

^D

a small creature came to live in once upon a time the forest.


Now let’s assume that we already have our text inside a file called story.txt. We can use that file as input to the sort program by redirecting the input with the “<” character. The sort doesn’t know the difference. Our output is the same:


$ sort < story.txt a small creature came to live in once upon a time the forest.


1.3.1.2 Pipes

The output from one command can also be sent directly to the input of another command. Such a connection is called a pipe. Linux command-line users also use “pipe” as a verb, describing a sequence of commands as piping the output of one command into another. Some examples:


$ ls | wc > wc.fields

$ java MyCommand < data.file | grep -i total > out.put


The first example runs ls, then pipes its output to the input of the wc program. The output of the wc command is redirected to the file wc.fields. The second example runs java, giving it a class file named MyCommand. Any input that this command would normally read from keyboard input will be read this time from the file data.file. The output from this will be piped into grep, and the output from grep will be put into out.put.

Don’t worry about what these commands really do. The point of the ex- ample is to show how they connect. This has wonderful implications for devel- opers. You can write your program to read from the keyboard and write to a window, but then, without any change to the program, it can be instructed to read from files and write to files, or be interconnected with other programs.

This leads to a modularization of functions into small, reusable units. Each command can do a simple task, but it can be interconnected with other com- mands to do more, with each pipeline tailored by the user to do just what is needed. Take wc for example. Its job is to count words, lines, and characters in a file. Other commands don’t have to provide an option to do this; any time you want to count the lines in your output, just pipe it into wc.