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]
$ echo "Next year will be 19`expr \`date +%y\` + 1`."
Next year will be 1997.
$ date +%y
96
$ expr 96 + 1
97
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:
2>&1
|
$ 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
.