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.

The Author

Martin Streicher is the founder of Locomotive, a creative coding cooperative based on Ruby on Rails. When not writing prose or code, he dreams of becoming a famous comic book author. You can reach Martin at mailto:martin.streicher@gmail.com.

Buy this article as PDF

Express-Checkout as PDF

Pages: 4

Price $2.95
(incl. VAT)

Buy Raspberry Pi Geek

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content