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.