One of the shell's most important features is it's ability to redirect the standard input and standard output of any program. Programs that ordinarly write to the screen can have that output sent to a file. Programs that ordinarly read from the keyboard can have their input redirected from a file. For example
$ prog >afile.txt
Now afile.txt
contains the text that prog would
have displayed on the screen.
$ prog <bfile.txt
Now prog reads its input from bfile.txt
rather
than from the keyboard.
Both the input and the output can be redirected.
$ prog <bfile.txt >afile.txt
The I/O redirection part of the command line is not sent to the program. As far as prog is concerned in the examples above, it is being executed with no arguments. If prog wants arguments, they can be put on the command line anywhere relative to the I/O redirection operators. For example
$ prog <bfile.txt arg1 >afile.txt $ prog arg1 >afile.txt <bfile.txt $ prog > afile.txt < bfile.txt arg1
all do the same thing.
Ordinarily when output redirection is used, the shell truncates the output file to zero size first if it already exists. Commonly you want to append the new output to the end of the file. This can be done with the '>>' operator. For example
$ echo "Finished processing on `date`" >>$HOME/results
This saves the current date (and time) into the file results
in the
home directory. It adds a new record onto the end of any existing records.
Many Unix programs that process the data inside files will accept the name of the
file(s) to process on the command line. If there are no such names presented, a typical Unix
program will process whatever it finds at its standard input. Consider the commands below.
They both search the file afile.txt
looking for lines that contain the
string "Peter."
$ grep 'Peter' afile.txt $ grep 'Peter' < afile.txt
In the second case, the grep command does not see any file name on the command line. It thus reads it's standard input (which happens to be the same file as named in the first command).
This behavior allows you to test a program without creating a special data file. Just run it and type at it. For example
$ grep 'Peter' Hello. Anybody there? My name is Peter. My name is Peter. What's your name? Is it Peter also? Is it Peter also? ^D $
The '^D' (control+D) causes the terminal to generate an EOF character. Notice how grep printed out lines that contained the string 'Peter.'
The shell allows you to direct the standard output of one program into the standard input of another. This is done with the pipe operator '|.' This ability, coupled with the behavior described above, makes the Unix system powerful. For example
$ ls -l | grep '^d'
This command displays all lines in the output of the ls -l command that start with a 'd'. Such lines are entries for subdirectories.
$ who | wc -l
This command sends the output of who to the word count program to count the number of lines in who's output. The result is a count of the number of users logged into the system.
$ prog args | mail pchapin
This command mails the output of the prog command to pchapin. This works because the mail program accepts the message to be mailed at it's standard input.
It is possible to redirect or pipe the output of entire loops. For example
$ for FILE in * > do > process $FILE > echo "Done with $FILE on `date`" > done > $HOME/results $
Note the redirection done after the 'done' keyword. All the output generated within the
loop (except for stuff explicitly redirected) is put into
$HOME/results
. This is faster and cleaner than redirecting with append
each command within the loop.
Pipes are also possible.
$ for FILE in * > do > process $FILE > done | sort > $HOME/results $
When you redirect the output of a loop, the loop is run in a subshell. This may be significant if the point of the loop is to set shell variables.