sections in this module City College of San Francisco - CS160B
Unix/Linux Shell Scripting
Module: Scripting Basics2
module list

Command Substitution

Command substitution allows you to embed one Unix command on the commandline of another. The embedded command is run first, then its standard output is placed (command-substituted onto) the commandline of the main command.

Suppose you want to report how many people are currently logged in by generating a message like this

echo "There are XXX users currently logged in."

We all know how to get the information we need: just count the number of lines in the output of who:

$ who | wc -l
13

The number 13 was output to standard output by wc -l using standard output. To generate our message we can simply run this command place its output on the commandline of our echo command using command substitution

$ echo "There are $(who | wc -l ) users currently logged in."
There are 13 users currently logged in.
$

Using command substitution can create unwieldy commands. If our output message in the example above was longer, or if the command we were substituting was longer, the resulting command would be difficult to read and to write. Thus, in a shell script it is often preferable to use command substitution to initialize a variable, then use variable substitution in the final command:

-bash$ nu=$(who | wc -l)
-bash$ echo "There are $nu users currently logged in."
There are 13 users currently logged in.
-bash$

Remember that everything that the command outputs to standard output is substituted. Suppose we wanted to output the number of lines in the file $file. You might decide to use the wc -l command to generate the number like this:

$ nl=$(wc -l "$file")

But when you use the resulting variable in your message, you get a strange result:

$ echo "There are $nl lines in $file"
There are 15 tick lines in tick
$

This is because the wc command also outputs the name of the file! In some cases you can control this behavior by knowing a bit about your command. In wc's case, it will only output the name of the file if it knows it. If we rewrite our command so that the shell opens standard input for wc, we get what we want:

$ nl=$(wc -l < "$file")
$ echo "There are $nl lines in $file"
There are 15 lines in tick
$

(It may be more obvious if we rewrote the command like this:

nl=$(cat "$file" | wc -l) 

but the result is the same.)

As an aside, I should mention that a command-substituted command is really a full command. It is processed recursively using the same set of rules as a regular command. For example, in the command below:

echo "There are $(cat "$file" | wc -l) lines in $file"

there is no ambiguity about the double quotes. The outer double quotes belong to the enclosing command and the inner set (around $file) belong to the command being substituted. Each set is totally independent. In the similar command

echo "There are $(cat $file | wc -l) lines in $file"

the variable $file is expanded outside of quotes!

POSIX-syntax vs. backquotes

The traditional syntax for command substitution was to enclose the command to be subtituted in backquotes, like this:

`ls`

The biggest reason to avoid using backquotes is that the backquote may be rendered as single-quotes in some fonts and on some printers. Even when the backquote is a different character, it may appear so light that it is easily missed. The POSIX notation of enclosing the command being substituted in $( ) is much easier to see.

The other reason to use the new POSIX notation is that it nests. Although it should be avoided if possible for clarity, there are situations where you must embed command substitution inside command substitution. This is impossible when using backquotes due to ambiguity, e.g.,

cmd3 $(cmd2  $(cmd1))

can be understood, but,

cmd3 `cmd2 `cmd1``

cant.

Preview question: We would like our shell scripts to run as standard Unix commands. This means that information to tell our shell script what to do should come from the commandline. This is accomplished via argument variables, or positional parameters, as we see in the next section.

Prev This page was made entirely with free software on Linux:  
Kompozer
and Openoffice.org    
Next

Copyright 2016 Greg Boyd - All Rights Reserved.

Document made with Kompozer