Redirection

When you run a command, you sometimes want to store the output of that command into a file. Alternatively, you may also wish to use the contents of a file as the standard input to a command. In other cases, you may need to pass the output of a command as input to another command, and get the final result afterward. These kinds of input/output manipulations are supported by the redirection features of the C-Shell. Unix commands are not aware of the I/O redirection symbols. They simply receive their input as though it is being typed into the terminal (standard input). The csh redirection features allow you to:

Here is a table that lists some I/O redirection operators and describes their actions:

Operator Description
>file Directs the standard output to file
>>file Appends the standard output to the end of file
<file Takes the standard input from file
<<string Take standard input until the next occurrence of string at the beginning of a line (also called a here document)

Let us have a look at each one of them.

Output Redirection

Output redirection allows us to save a process' output into a file. This file can then be listed, printed, edited, or used as input to a future process. To send the output of a command into a file, we type:

command > filename

Csh will create the file filename if it doesn't exist, or overwrite its contents if it already exists. If the user does not have write permission to the directory containing filename, then an error message is produced. Read the next example and see if you understand what it does:

#!/bin/csh 
# scriptV.csh 
echo -n Please enter the name of the file: 
set filename = $< 
echo -n Please enter the content: 
set content = $< 
echo $content > $filename 

% scriptV.csh 
Please enter the name of the file: example.txt 
Please enter the content: Hello World! 

% cat example.txt
Hello World! 

The script scriptV.csh creates a new file whose name is specified by the user. It then reads a string typed in by the user, and uses echo to write the string to the given file, by redirecting the standard output of echo to that file. This script assumes that the user wants to create a new file and thus no permission check is performed. However, you should always perform permission checks using file-oriented expressions before you write to, read from, or execute a file in your script. Consider the following example which also uses the > to redirect output:

% cat file1 file2 file3 >tempfile 
% 
This example combines the contents of the three files, file1, file2, and file3 into the tempfile file. Again, if tempfile does not yet exist, it is created; if tempfile already exists, its contents are overwritten.

The second form of output redirection uses >>. The >> symbol appends the output of a command to the specified file. For example, the command:

% cat file1 file2 file3 >>tempfile 
% 
adds the contents of the file1, file2, and file3 to the end of the tempfile file. If tempfile does not exist, it will be created when the command is issued.

Input Redirection

Input redirection is useful because it allows you to prepare a process' input beforehand and store it in a file for later use. The most common form of input redirection uses < as in:

command < filename
This form executes command using the contents of the file filename as its standard input. If the file does not exist or the user does not have read permissions on it, an error occurs. As an example, the following script asks for a filename and then prints out the contents of the file:
#!/bin/csh 
# scriptVI.csh 
echo -n Please enter a filename: 
set filename = $< 
if ( ( -e "$filename" ) && ( -r "$filename" ) ) then 
    echo < $filename 
else 
    echo $filename does not exist or it is not readable 
endif 

% scriptVI.csh 
Please enter a filename: example.txt 
Hello World! 

% scriptVI.csh 
Please enter a filename: practice.txt 
practice.txt does not exist or it is not readable 

Unlike scriptV.csh, this script makes sure that the given file exists, and that the user is allowed to read the file, before it uses its contents as the standard input to echo. Here is another example:

% who > tempfile 
% sort < tempfile 
amy pts/123 Jun 12 22:46 (bowen.ugrad.cs.ubc.ca) 
joel pts/127 May 29 11:32 (valdes.ugrad.cs.ubc.ca) 
zack pts/125 Jun 10 13:12 (pender.ugrad.cs.ubc.ca) 
zane pts/121 Jun 11 14:14 (xt535a.ugrad.cs.ubc.ca) 
% 
The who command prints a listing of the users logged on to a server. The sort command sorts its input alphabetically (and in other ways. Check its man page). Thus, the first command writes a listing of the users that are currently logged in to the system to the tempfile file. The second command then sorts the listing of users from the tempfile file alphabetically and displays them on the terminal.

The last I/O redirection symbol is <<. This symbol is used to produce what is called a here document. It appends all of the input that it receives, until a certain character is reached. For example:

% cat <<EOF >junk.txt 
? Hello. 
? This is a test file. 
? EOF 
% cat junk.txt 
Hello. 
This is a test file. 
% 
This command caused the shell to read the standard input up until the string EOF began a new line. The cat command then prints the lines that were typed to the standard output, which is redirected by the shell to write to the file junk.txt. This is a quick and easy way to create a new file.

What happens if you mistype a command while using I/O redirection? The results vary depending on which I/O redirection symbol is used. For example, the commands:

% ls 
main.html 
image.gif 
% woh >tempfile 
woh: Command not found 
% ls 
main.html 
image.gif 
tempfile 
% 
show that the shell interprets the special symbol > before attempting to invoke the command. In this case, the who command was mistyped. Since the command was mistyped, it was not executed and did not modify the newly created tempfile. The result is a new empty file named tempfile.

Pipelines

Although many commands in Unix are fast and useful by themselves, there are times when one command cannot do a job for you. Such tasks may require different types of processing. Since most Unix utilities have very specific behaviour and processing capabilities, you may frequently want to combine commands together into a pipeline. A pipeline can contain as many commands as you like and the output of one program becomes the input of the next program in the pipeline. We have already seen in the previous section about I/O redirection how we can write the output of a command to a file and then use this file as the input for another command. A pipeline does essentially the same thing, but in one command instead of two. For instance, typing:

command1 | command2

causes the standard output of command1 to "flow through" to the standard input of command2. This is the same as typing:

% command1 > /tmp/aTemporaryFile 
% command2 < /tmp/aTemporaryFile 
% rm /tmp/aTemporaryFile 

but it is much shorter. Using pipes, you can solve a large task by breaking it into a series of smaller tasks, and then chaining the small tasks in sequence. In the next example, the output of the ls command is piped to the wc command in order to count the number of files in the current directory:

% ls 
someFile.C    someFile.h        someObj.o    executable* 

% ls | wc -w 
4 
Here is an illustration of the flow of the data used:
ls --> wc --> Terminal
Let us look at another example:
% who | grep joel 
joel pts/127 May 29 11:32 (valdes.ugrad.cs.ubc.ca) 
% 

This pipeline checks to see if joel has logged into the system. Here is a slightly more complex example:

% ps -ef | grep joel 
joel 5189 5184 1 19:12:33 pts/7 0:01 csh 
joel 5238 5189 0 19:12:37 pts/7 0:00 emacs 
joel 5247 5198 0 19:12:35 pts/7 0:00 grep joel 
% 

This command prints out all of the processes that are being run by joel. The ps command invoked with the -ef option prints out all of the processes that are being run on the system. The grep command is used to filter the list, leaving only the processes being run by joel.

Here is an example that combines three commands:

% who | grep joel | wc -l 
1 
% 

This command counts the number of times that joel is logged into the server.

From the above examples, it may seem like commands are run one after the other. If the commands were run one after the other, many users using pipelines to combine commands would consume too many of the systems resources. Instead, the commands in a pipeline are actually run at the same time. The Unix kernel handles the synchronization between commands that is needed for a pipeline to work properly. The kernel is the core part of the operating system that provides the most basic services. Without the kernel to drive it, the system would not be able to function. The kernel provides services such as process management (which processes are doing what) and memory management (where in memory said processes reside). The Unix kernel is an incredibly complex program that was first written in the C programming language in 1973.

While working in a X terminal window, you may have mistyped a command at one time or another. You should notice that Unix replies with an error message printed to the terminal when a command has been invoked with incorrect arguments. Such is often the case when a typo occurs. Why is it that when a command is entered in error and combined with others in a pipeline, the error message still gets printed to the terminal instead of staying in the pipeline and causing havoc with the other commands? This is because errors are handled separately by the shell from input and output. Here is a diagram to explain further:

Standard Input ------> Command, Options------> Standard Output
                                  |
				  |			
                                  |
				  |
                                 \ /
				  v
                            Standard Error

All Unix commands behave according to the above diagram. They take arguments from the standard input, and produce results on standard output. Any errors that occur while issuing the command are sent to the standard error. By default the standard input, standard output, and standard error all refer to the terminal. We have seen how the shell can be used to redirect both the standard input and standard output in the previous section about I/O redirection. Redirecting the standard error is possible, but will not be discussed here.