Input/Output Streams and Redirection
Up until now, all of the commands that we’ve used have accepted input directly from you via command-line arguments. While this is sufficient for many tasks, it does greatly limit the amount of larger-scale data processing that you can do. If we want to perform some more sophisticated data processing, and really unlock the power of the command line interface, we’ll need to begin to work with more sophisticated forms of input and output.
The sort command
As an example of a command that is most useful when using files for input and
output, we will consider sort
, which we’ve already seen before, briefly, in
the first chapter of this tutorial.
The simplest use of the sort
command is without any arguments. At first
glance, this will not appear to do anything.
% sort
In reality, sort
is currently waiting for some data to process. When running
sort in this way, the input is expected to come from the keyboard. So you’ll
need to manually type some text into the terminal. Like most filters, sort
is
line oriented, so enter a few lines of text. Then, signal that you are done
with ^Z. sort
will then sort your input and report the results back to you.
% sort
hello
goodbye
test
and more
^Z
and more
goodbye
hello
test
Of course, this particular example of sort
is not very useful. For one thing,
it requires you to manually type the data that you want sorted. For another, it
reports the result of sorting directly on the command line. It would be better
if you could read the data automatically from a file, and then output the
results directly to a file. That’s what we’ll do next.
Standard Input and Standard Output
Every process that is launched on a computer is launched with three files
automatically open: standard input (stdin), standard output (stdout), and
standard error (stderr). By default, standard input is connected to the input
buffer of your terminal, and standard output and standard error are connected
to the output buffer. That is why, in the sort
example above, it accepts
input from whatever you type, and reports the results of the sorting directly
on the terminal.
The shell will allow you to change this default mapping using input and output
redirection. If you’d like for a command’s standard input to come from a file,
rather than the terminal, you want to use the input redirection operator: <
.
To make the output go to a file instead of the terminal, you can use the output
redirection operator: >
.
Input Redirection
For example, let’s create a file using notepad and then use sort
to
sort it. First, create a file called tosort.txt
in Notepad with the
following contents,
b
c
d
g
k
l
q
u
a
l
A
1
2
ad
L
To demonstrate input redirection first, run sort
like so,
% sort < tosort.txt
1
2
a
A
ad
b
c
d
g
k
l
l
L
q
u
You should see the sorted contents of the file appear on the terminal after your call to sort.
Notice that the command no longer paused for input. This is because the redirection of standard input caused it to read from the file, instead of the terminal input buffer. Every file contains an implicit EOF (^Z) at the end of it, so the command read each line from the file, encountered the EOF, and ran the sort–all without any explicit user-interaction required. You can imagine how useful this is for process very large files.
Many commands which process files do not actually require input redirection of this form, and will actually allow you to specify a filename directly as an argument instead. For example, you could’ve executed the above command with an argument, rather than a redirection, like so,
% sort tosort.txt
and gotten the same result. Input redirection is probably the least commonly used form of redirection for this reason. But it’s still worth being aware of it.
Output Redirection
The above command displayed the results of sorting directly on the terminal. But if our file is sufficiently large, it might be more useful to create a new file containing the sorted results. We could copy and paste from the terminal into a Notepad window, but that is overly manual (not to mention, some very large files may completely fill the terminal’s output buffer and be cut off).
We can tell the shell to redirect the command’s output to a file like so,
% sort < tosort.txt > sorted.txt
Note that we have specified both an input and an output redirect in the same command. This is perfectly valid.
The command will no longer produce output on the terminal, as we’ve redirected
its output from the output buffer to a file. However, we can easily see the
results of our sort by using type
,
% type sorted.txt
1
2
a
A
ad
b
c
d
g
k
l
l
L
q
u
Error Redirection
The third standard file that is opened is called standard error. Despite the name, it is used for more than error messages. A lot of information messages are written to standard error, as are prompts written by commands (as opposed to the shell). Standard error is used so that messages from commands that are using output redirection remain visible on the terminal, or to allow you to write errors to a different location than output. For example, should sort report an error for some reason, you don’t necessarily want that error message being written to the same file as the sorted data.
As an example of a carguments, will write the name of each file to stderr.ommand that writes data to standard error, the type
command, when provided multiple files as arguments, will write the name of each file to stderr. For
example,
% type t1.txt t2.txt t3.txt
t1.txt
this is file 1
with two lines
t2.txt
and this is file2
t3.txt
Any, finally, file
3 is here.
We can verify that these headers are in fact going to stderr by redirecting stdout to a file.
% type t1.txt t2.txt t3.txt > merged.txt
t1.txt
t2.txt
t3.txt
This allows us to see file headers when using type
interactively, while also
allowing us to use type
to merge files together, without introducing any
extra lines into the merged file.
If we wanted to redirect the error messages, leaving the file contents going
to the terminal, we can do that with the standard error redirection operator,
2>
, like so,
% type t1.txt t2.txt t3.txt 2> headers.txt
this is file 1
with two lines
and this is file2
Any, finally, file
3 is here.
% type headers.txt
t1.txt
t2.txt
t3.txt
We can also send both stdout and stderr to the same file if you want. To do
this, first redirect stdout, and then follow up with 2>&1
, which will tell
the shell to send stderr to the same spot as stdout,
% type t1.txt t2.txt t3.txt > headers.txt 2>&1
Note that you must put the output redirect first, and then the error redirect, or it will not work properly.
Conclusion
In this chapter, we discussed using input and output redirection to make a command read input from a file, or write output to a file (or both). In the next chapter, we’ll follow up on this by discussing more commands which work well with input and output redirection, as well as a related concept called a pipeline, which allows us to link several such commands together.