Combining commands with pipes and redirection
Bit Bucket
As you've seen, most commands emit output of one kind or another. Most command-line commands use stdout and stderr to show progress and error messages, in that order. If you want to ignore that sort of output – which is useful, because it often interferes with working at the command line – redirect your output to the "bit bucket," /dev/null
. Bits check in, but they don't check out.
Listing 3 shows a simple example. If you redirect the standard output of cat
to /dev/null
, nothing is displayed. (All the bits are thrown into the virtual vertical file.) However, if you make a mistake, error messages, which are emitted to standard error, are displayed. If you want to ignore all output, use the >&
operator to send stdout and stderr to the bit bucket.
Listing 3
The Bit Bucket
$ ls secret.txt $ cat secret.txt I am the Walrus. $ cat secret.txt > /dev/null $ cat socrates.txt > /dev/null cat: socrates.txt: No such file or directory $ cat socrates.txt >& /dev/null $ echo Done. Done.
You can also use /dev/null
as a zero-length file to empty existing files or create new, empty files (Listing 4).
Listing 4
Empty Files
$ cat secret.txt Anakin Skywalker is Darth Vader. $ cp /dev/null secret.txt $ cat secret.txt $ echo "The moon is made of cheese!" > secret.txt $ cat secret.txt The moon is made of cheese! $ cat /dev/null > secret.txt $ cat secret.txt $ cp /dev/null newsecret.txt $ cat newsecret.txt $ echo Done. Done.
Other Tricks
In addition to redirection, the shell offers many other tricks to save time and effort.
The "back tick" or "back quote" operator (`
… `
) expands commands in place. A phrase between back ticks runs first, while the shell interprets the command line, and its output replaces the original phrase. You can use back ticks to yield, for example, a file name or a date:
$ ps > state.`date '+%F'` $ ls state* state.2009-11-21 $ cat state.2009-11-21 13842 ttys001 0:00.54 -bash 30600 ttys001 1:57.15 ruby ./script/server $ cat `ls state.*` 13842 ttys001 0:00.54 -bash 30600 ttys001 1:57.15 ruby ./script/server
The first command line captures the list of running processes in a file named something like state.YYYY-MM-DD
, where the date portion of the name is generated by the command date '+%F'
. The single quotes around the argument prevent the shell from interpreting +
and %
. The last command shows another example of the back tick. The evaluation of ls state.*
yields a file name.
Speaking of capturing results, if you want to capture the output of a series of commands, you can combine them within braces ({
… }
):
$ { ps; w } > state.`date '+%F'`
In the preceding command, ps
runs, followed by w
(which shows who is using the machine), and the collected output is captured in a file.
You can also embed a sequence of commands in parentheses to achieve the same result, with one important difference: The series of commands collected in parentheses runs in a subshell and does not affect the state of the current shell. For example, you might expect the commands
{ cd $HOME; ls -1 }; pwd (cd $HOME; ls); pwd
to produce the same output. Note, however, that the commands in braces change the working directory of the current shell. The latter technique is inert.
The decision to use a combination or a subshell depends on your intentions, although the subshell is a much more powerful tool. You can use a subshell to expand a command in place, just as you can with back ticks. Better yet, a subshell can contain another subshell, so expansions can be nested. The two commands
$ { ps; w } > state.$(date '+%F') $ { ps; w } > state.`date '+%F'`
are identical. The $( )
runs the commands within the parentheses and then replaces itself with the output. In other words, $( )
expands in place, just like back ticks; however, unlike back ticks, $( )
can be very complex and can even include other $( )
expansions:
$ (cd $(grep strike /etc/passwd | \ cut -f6 -d':'); ls)xw
This command searches the system password file to find an entry for user strike
, clips the home directory field (field six, if you count from zero), changes to that directory, and lists its contents. The output
grep /etc/passwd strike | cut -f6 -d':'
is expanded in place before any other operation. Because the subshell has so many uses, you might prefer to use it instead of the { }
or the back tick operators.
« Previous 1 2 Next »
Buy this article as PDF
Pages: 4
(incl. VAT)