1. Introduction
Whenever we work on the Linux command line, we often have to pass data from one command to another, like feeding a list of find results into a grep. This is where streams come into play.
In this tutorial, we'll take a look at what streams are and how we work with them.
2. What are Streams
We can think of a stream in its simplest form as a pipe that carries data – especially character data – from one point to another.
Some examples of input streams are the keyboard, text data stored in files and input from I/O devices. We can deliver output to files, commands, windows, and other I/O devices.
3. Sample Data
Let's create some sample files to use in the subsequent sections:
$ echo -e "tables\nladders\nchairs" > streamdata1 $ echo -e "planes\ntrains\nautomobiles" > streamdata2
We've created the streamdata1 and streamdata2 files and populated them with some data:
$ cat streamdata1 tables ladders chairs $ cat streamdata2 planes trains automobiles
4. Redirecting Input
The first stream that we're going to look at is STDIN.
STDIN refers to the standard input stream; usually, input from the keyboard. STDIN has a filehandle of 0 (zero).
The < operator is used to pass input from a file or I/O device data to a command.
Let's say that we want to count the number of lines in a file without passing the file name through as a parameter to the wc command. We can do it by redirecting STDIN:
$ wc -l < streamdata1
5. Redirecting Output
Next, let's take a look at STDOUT, the standard output stream. All output from this stream is typically sent to our terminal window. The filehandle for STDOUT is 1.
The > operator is used to direct output from a command to a source; usually a file. By default, a single > will:
- Create a new file if it doesn't already exist
- Overwrite any pre-existing data in the file if the file already exists
Let's see how we can use the cat command to emit the contents of streamdata1 and send the output to a new file:
$ cat streamdata1 > combinedstreamdata
When we print the contents of the combinestreamdata file it should look exactly like streamdata1:
$ cat combinedstreamdata tables ladders chairs
6. Appending to an Existing File
While > overwrites data, the >> operator preserves data by appending to an existing file.
Let's see how we can add the contents of streamdata2 to the combinedstreamdata file:
$ cat streamdata2 >> combinedstreamdata
The combinedstreamdata file now contains the contents of both our streamdata1 and streamdata2 files:
$ cat combinedstreamdata tables ladders chairs planes trains automobiles
7. Piping Output to Input
Chaining together multiple tasks is a common use case when working with Linux commands.
With the | (pipe) operator, we can chain many commands together by passing the output from one through as input to the next.
Let's try using the | operator to stream the output from the cat command to the input stream of the wc command:
$ cat streamdata2 | wc -l
8. Redirecting Error
Now that we've got the basics of stream redirection down, let's look at how we can work with multiple output files.
Let's attempt to execute a script that does not exist and pipe its imaginary output to a log file:
$ exec doesnotexist.sh > out.log
We get this error message:
exec: doesnotexist.sh: not found
Let's take a look and see what our command wrote to out.log:
$ cat out.log
Hmm, our log file is empty. But, we did see an error message – we might want to log that, too.
Let's see how we can redirect STDOUT and STDERR to capture the output and error output:
$ exec doesnotexist.sh >out.log 2>err.log
In the above statement, we direct standard output to out.log and standard error to err.log.
More specifically, we referenced the standard error stream using its filehandle – 2>err.log. We didn't have to specify the filehandle for standard output because its filehandle is the default.
Let's check to see what the command wrote to err.log:
$ cat err.log exec: doesnotexist.sh: not found
Our error message was successfully redirected to our error log file.
In this example, we handled both output streams (STDOUT, STDERR) and directed each to its own log file.
9. Merging Output and Error
Although we can direct STDOUT and STDERR to their own log files, we often prefer the simplicity of having a single log file to deal with.
The >& operator is a special operator that is used for directing output from one stream to another. We can use it to pipe the output of STDERR to STDOUT:
Let's see how we can leverage file handles and >& to give us a single log file that contains the output of STDOUT and STDERR:
$ cat streamdata1 streamdata2 streamdata3 2>&1>out.log
$ cat out.log tables ladders chairs planes trains automobiles cat: streamdata3: No such file or directory
As expected, the contents of streamdata1 and streamdata2 are found in out.log along with the anticipated error message since streamdata3 does, in fact, not exist.
10. Conclusion
In this tutorial, we looked at what Linux streams are and saw how to use them. We worked through a few scenarios that demonstrated the different capabilities of stream redirection.