Purging the process Part 1
Introduction to pipes, filters, and redirection, Part 1
Summary
If you've arrived at Unix from the graphical user interface (GUI) world of Windows or Mac OS, you're probably not familiar with pipes and filters. Even among character-based interfaces, only a few of them, such as MS-DOS, provide even rudimentary pipes and redirection.
Redirection allows a user to redirect output that would normally go to the screen and instead send it to a file or another process. Input that normally comes from the keyboard can be redirected to come from a file or another process.
Purging the process: Read the whole series! | |
---|---|
|
/dev/tty
, which is the device name for your terminal. The stdin file is assigned to the keyboard of your terminal, while stdout and stderr are assigned to its screen. Let's start with a simple example using
grep
. Type a grep
command to find lines containing the word hello, then type the following lines at your terminal. At the end of each line press Enter to move down to the next line. Watch what happens as you type say hello
. $ grep "hello" Now is the time for every good person to say hello.
The screen repeats the last line.
$ grep "hello" Now is the time for every good person to say hello. say hello.
Hold down the Control key and press D to end the input to
grep
. Control-D is an end-of-file marker and can be entered as a keystroke to stop any utility that is taking its input from the keyboard. The
grep "hello"
line is a command to search standard input for lines containing hello and echo any such line found to standard output. The Unix console automatically echoes anything you type, so the three lines appear on the screen as you type them. Then grep
hits a line containing hello and decides to output it to standard out, and say hello
appears on the screen a second time. The second appearance is the output from grep
. Standard output can be redirected to a file using the right angle bracket (
>
) as shown in the example below. The same grep
command is redirected to send its output to a file named junk.txt
. The say hello
line doesn't appear a second time because it's been directed to the junk.txt
file. After the user presses Control-D, cat
is used to display the contents of junk.txt
, which contains grep
's single output line. $ grep "hello" >junk.txt Now is the time for every good person to say hello. (type control-D here) $ cat junk.txt say hello. $
Standard input can be redirected to come from a file by using the left angle bracket (
<
). In order to demonstrate this, we need a file that can be used for input. Use vi to create the following sample file and save it as hello.txt
. Now is the time for every good person to say hello.
When you type the following command, notice that the output from
grep
is the single say hello
. Because input is being drawn from a file, you don't need to use Control-D to stop the process. $ grep "hello" <hello.txt say hello.
Both standard input and output are redirected in the following example. Once
grep
starts up, it takes its input from hello.txt
and outputs the result to junk.txt
. There is no output on the screen, but you can use cat
to display junk.txt
and verify the contents. $ grep "hello" <hello.txt>junk.txt $ cat junk.txt say hello. $
If a redirection to an output file encounters a file that already exists, that file is destroyed and a new one, containing the new output, is created, assuming the user has appropriate permissions to delete and create a new file. You can confirm this by using the previous example to search for a different line of text. In this example, the earlier version of
junk.txt
has been replaced with the new output from grep
, the single line Now is the time
$ grep "Now" <hello.txt >junk.txt $ cat junk.txt Now is the time $
There is a convention used in Unix programs which dictates that, if a file is expected as input to a program but no file is named on the command line, standard input is used. Because
grep
is designed to search for a string in a file, or files, it uses a command-line syntax that lets you name a file on the command line, and the input redirection symbol is not needed. Internally, grep
checks if a file is named on the command line and opens and uses it. If no file name is found, standard input is used. The following command lines for grep
have the identical effect. Internally, the first command reassigns
hello.txt
to standard input and uses it for input; the second command opens hello.txt
as a file and uses it for input. grep
doesn't expect an output file to be named on the command line. To get the output into a file, you must use output redirection. It doesn't hurt to redirect grep
input, but in the case of grep
, the redirection is already taken care of for you on the command line. $ grep "Now" <hello.txt >junk.txt $ grep "Now" hello.txt >junk.txt
If you want to preserve the existing output file and append new information to it, use a double right angle bracket (
>>
). The following example uses echo
, which normally outputs to the screen, to create the hello.txt
file without using an editor. The output of the echo
command is redirected into the file, and two more lines are appended to it. $ echo "Now is the time" >hello.txt $ echo "for every good person to" >>hello.txt $ echo "say hello." >>hello.txt $ cat hello.txt Now is the time for every good person to say hello. $
Pipes are created as a means of taking the output of one program and using it as the input to another. The pipe symbol (
|
) is used as a connector between the two programs. In the following example, look at the first part of the command up to the first pipe symbol. The cat
command normally outputs to the screen; in this case, however, the output has been sent into a pipe. On the righthand side of the pipe, this output becomes the input to grep "hello"
. The output from grep "hello"
is in turn sent into another pipe. On the right side of that pipe, the output is used as standard input to a sed
command that searches for hello and replaces it with bye. The final result is redirected to a file named result.txt
which cat
displays on the screen as say bye
. $cat hello.txt | grep "hello" | sed -e "s/hello/bye/" > result.txt $cat result.txt say bye. $
If this were broken down step by step using simple redirection, you would need several commands, as well as the final
rm
steps to clean up the intermediate work files that were created. $cat hello.txt >wrk1.txt $ grep "hello" <wrk1.txt >wrk2.txt $ sed -e "s/hello/bye/" <wrk2.txt >result.txt $cat result.txt say bye. $rm wrk1.txt wrk2.txt
The initial step of getting
hello.txt
into the grep
command could also be done in several other ways. Two examples are shown below. The first redirects input to grep
from hello.txt
on the lefthand side of the pipe; the second puts parentheses around the grep
and sed
commands, groups them as a subprocess, then redirects input and output to the grouped process. $ grep "hello" < hello.txt | sed -e "s/hello/bye/" > result.txt $( grep "hello" | sed -e "s/hello/bye/" ) < hello.txt > result.txt $
Redirecting standard error output
So far I've only shown you how to pipe and redirect standard output, but it's frequently useful to do something with error output. In the following example,
So far I've only shown you how to pipe and redirect standard output, but it's frequently useful to do something with error output. In the following example,
find
is being used to search the entire system (starting at /
) for files with a .txt
extension. Whenever one is found, its full directory entry is placed in a file named textfiles
. The example below shows sample error messages that are generated when find
attempts to access an unavailable directory. $ find / -name *.txt -exec ls -l {} \; >textfiles find: /some/directory: Permission denied find: /another/one: Permission denied $
The error messages can be suppressed by redirecting them to
/dev/null
, which is a special device that can be thought of as a wastebasket for bytes written to it on output. Everything that goes to /dev/null
disappears. To redirect standard error, use a right angle bracket preceded by a 2, which is the file descriptor number for standard error. If you don't care about error messages, send them to the /dev/null
byte bucket. $ find / -name *.txt -exec ls -l {} \; 2>/dev/null >textfiles $
The following command combines redirection and pipes to extract and bring a full list of all
.txt
files sorted in order by the third field in the ls -l
directory entry, the owner's name. $ find / -name *.txt -exec ls -l {} \; 2>/dev/null |sort -k 3 >textfiles $
Shell scripts can also redirect their output, so the above command could be put into a shell script without redirection, but the output can be redirected when the command is executed.
#!/usr/bin/sh # usertexts # outputs a listing of texts files on the system, ordered by owner id find / -name *.txt -exec ls -l {} \; 2>/dev/null |sort -k 3
This shell's script could be executed with the output redirection done at the shell script level.
$ usertexts >textfiles $
Pipes and redirection can be combined to create very powerful tools that start a text stream and then apply different tools to that stream, filtering it as it passes through different processes.
Next month, I'll take a look at more advanced uses of pipes and redirection.
0 comments:
Post a Comment