home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  

Unix Power ToolsUnix Power ToolsSearch this book

36.24. Nested Command Substitution

Section 28.14 introduced command substitution with a pair of backquotes (''). Let's review. The shell runs a backquoted string as a command, then replaces the string with its output. Sometimes -- though not as often -- you'll want to use the results from one backquoted string as arguments to another command, itself also inside backquotes. To do that, you need to nest the backquotes to tell the shell which command (which set of backquotes) should be done first, with its output given to the second command. This is tricky with backquotes; the Korn shell introduced an easier way that you'll see below. Here's a simple example -- the first command line uses nested backquotes, and the next two commands show its parts:[116]

[116]True, this won't work after 2008. Also true, most shells have built-in arithmetic, and some can zero-pad results. But this is a simple example!

$ echo "Next year will be 200`expr \`date +%y\` + 1`."
Next year will be 2002.
$ date +%y
$ expr 01 + 1

The command to run first has escaped backquotes (\'\') around it. In the example above, that's the date +%y command. date +%y outputs the year -- in this case, 01 -- and that value is passed to the expr command. expr adds 01 and 1 to get 2. Then that result (from the outer backquotes) is passed to echo, on its command line, and echo prints the message.

Why does the inner command, inside the escaped backquotes (\'\'), run first? It's because the backslash before the backquote turns off the special meaning (Section 27.12) of the backquote. When the shell first evaluates the command line, which backquotes does it see? It sees the unescaped backquotes, the ones around the expr command, and the shell runs the command:

expr `date +%y` + 1

But when the shell evaluates that command line, it sees the backquotes in it (now unescaped) and runs that command -- date +%y. The date +%y command outputs 01. Next, the shell can finish the command expr 01 + 1. It outputs 2. Then the echo command can print its message.

Whew. Most newer Bourne-type shells have an easier way: the $(command) operators. Use $( before the command, where you would use an opening backquote. Put the ) after the command, in place of a closing backquote. You don't have to escape these operators when you nest them.

Here's the previous example with $( ), then a more real-life example:

2>&1 Section 36.16

$ echo "Next year will be 200$(expr $(date +%y) + 1)."
Next year will be 2002.

$ tarout=$(tar cf /dev/rst1 $(find . -type f -mtime -1 -print) 2>&1)
    time passes...
$ echo "$tarout"
tar: ./files/145923: Permission denied

The inner command -- in this case, the find (Section 9.1) -- is run first. Its output, a list of filenames, is put on the command line of the tar (Section 38.2) command. Finally, the output of tar (in this case, an error message) is stored in the tarout shell variable.

Beginners (and some long-time programmers too) might argue that you should never nest command substitution because it's too confusing. I think there are times nesting is clearer. It's more compact and doesn't need temporary storage. And it's not that hard to understand once you see what's happening. There's another nice example in Section 24.16.

-- JP

Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.