UNIX Power Tools

UNIX Power ToolsSearch this book
Previous: 45.30 Grabbing Parts of a String Chapter 45
Shell Programming for the Initiated
Next: 45.32 A Better read Command: grabchars

45.31 Nested Command Substitution

Article 9.16 introduces 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: [5]

[5] True, this won't give the right answer after 1998. True, the Korn shell has built-in arithmetic. But this is a simple example!

$ echo "Next year will be 19`expr \`date +%y\` + 1`."
Next year will be 1997.
$ date +%y
$ expr 96 + 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, 96 - and that value is passed to the expr command. expr adds 96 and 1 to get 97. 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 (8.14) of the backquote. So, when the shell first evaluates the command line (8.5), 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 96. Next, the shell can finish the command expr 96 + 1. It outputs 97. Then the echo command can print its message.

Whew. If you use the Korn shell or bash, there's 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:


$ echo "Next year will be 19$(expr $(date +%y) + 1)."
Next year will be 1997.
$ 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 (17.1) -is run first. Its output, a list of filenames, is put on the command line of the tar (20.1) 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 article 38.13.

- JP

Previous: 45.30 Grabbing Parts of a String UNIX Power ToolsNext: 45.32 A Better read Command: grabchars
45.30 Grabbing Parts of a String Book Index45.32 A Better read Command: grabchars
