Connecting Two Programs by Using Output As Arguments

Problem

What if one of the programs to which you would like to connect with a pipe doesn’t work that way? For example, you can remove files with the rm command, specifing the files to be removed as parameters to the command:

$ rm my.java your.c their.*

but rm doesn’t read from standard input, so you can’t do something like:

find . -name '*.c' | rm

Since rm only takes its filenames as arguments or parameters on the command line, how can we get the output of a previously-run command (e.g., echo or ls) onto the command line?

Solution

Use the command substitution feature of bash:

$ rm $(find . -name '*.class')
$

Discussion

The $() encloses a command that is run in a subshell. The output from that command is substituted in place of the $() phrase. Newlines in the output are replaced with a space character (actually it uses the first character of $IFS, which is a space by default, during word splitting), so several lines of output become several parameters on the command line.

The earlier shell syntax was to use back-quotes instead of $()for enclosing the sub-command. The $() syntax is preferred over the older backward quotes `` syntax because it easier to nest and arguably easier to read. However, you will probably see `` more often than $() especially in older scripts or from those who grew up with the original Bourne or C shells.

In our example, the output from find, typically a list of names, will become the arguments to the rm command.

Warning: ...

Get bash Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.