Chapter 12. Command Substitution
Command substitution reassigns the output of a command or even multiple commands; it literally plugs the command output into another context.
The classic form of command substitution uses backquotes (`...`). Commands within backquotes (backticks) generate command-line text.
script_name=`basename $0`
echo "The name of this script is $script_name."
|
rm `cat filename`
textfile_listing=`ls *.txt`
echo $textfile_listing
textfile_listing2=$(ls *.txt)
echo $textfile_listing2
|
 |
Command substitution invokes a subshell.
|
 |
Command substitution may result in word splitting.
COMMAND `echo a b`
COMMAND "`echo a b`"
COMMAND `echo`
COMMAND "`echo`"
|
Even when there is no word splitting, command substitution can remove trailing newlines.
mkdir 'dir with trailing newline
'
cd 'dir with trailing newline
'
cd "`pwd`"
cd "$PWD"
old_tty_setting=$(stty -g)
echo "Hit a key "
stty -icanon -echo
key=$(dd bs=1 count=1 2> /dev/null)
stty "$old_tty_setting"
echo "You hit ${#key} key."
|
|
 |
Using echo to output an unquoted variable set with command substitution removes trailing newlines characters from the output of the reassigned command(s). This can cause unpleasant surprises.
dir_listing=`ls -l`
echo $dir_listing
echo "$dir_listing"
|
|
Command substitution even permits setting a variable to the contents of a file, using either redirection or the cat command.
variable1=`<file1`
variable2=`cat file2`
echo "` <$0`"
|
if [ -f /fsckoptions ]; then
fsckoptions=`cat /fsckoptions`
...
fi
if [ -e "/proc/ide/${disk[$device]}/media" ] ; then
hdmedia=`cat /proc/ide/${disk[$device]}/media`
...
fi
if [ ! -n "`uname -r | grep -- "-"`" ]; then
ktag="`cat /proc/version`"
...
fi
if [ $usb = "1" ]; then
sleep 5
mouseoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=02"`
kbdoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=01"`
...
fi
|
 |
Do not set a variable to the contents of a long text file unless you have a very good reason for doing so. Do not set a variable to the contents of a binary file, even as a joke.
Example 12-1. Stupid script tricks
#!/bin/bash
exit 99
dangerous_variable=`cat /boot/vmlinuz`
echo "string-length of \$dangerous_variable = ${#dangerous_variable}"
exit 0
|
Notice that a buffer overrun does not occur. This is one instance where an interpreted language, such as Bash, provides more protection from programmer mistakes than a compiled language.
|
Command substitution permits setting a variable to the output of a loop. The key to this is grabbing the output of an echo command within the loop.
Example 12-2. Generating a variable from a loop
#!/bin/bash
variable1=`for i in 1 2 3 4 5
do
echo -n "$i"
done`
echo "variable1 = $variable1"
i=0
variable2=`while [ "$i" -lt 10 ]
do
echo -n "$i"
let "i += 1"
done`
echo "variable2 = $variable2"
exit 0
|
 |
The $(...) form has superseded backticks for command substitution.
output=$(sed -n /"$1"/p $file)
File_contents1=$(cat $file1)
File_contents2=$(<$file2)
|
The $(...) form of command substitution treats a double backslash in a different way than `...`.
bash$ echo `echo \\`
bash$ echo $(echo \\)
\
|
The $(...) form of command substitution permits nesting.
word_count=$( wc -w $(echo * | awk '{print $8}') )
|
Or, for something a bit more elaborate . . .
Example 12-3. Finding anagrams
#!/bin/bash
E_NOARGS=86
E_BADARG=87
MINLEN=7
if [ -z "$1" ]
then
echo "Usage $0 LETTERSET"
exit $E_NOARGS
elif [ ${#1} -lt $MINLEN ]
then
echo "Argument must have at least $MINLEN letters."
exit $E_BADARG
fi
FILTER='.......'
Anagrams=( $(echo $(anagram $1 | grep $FILTER) ) )
echo
echo "${#Anagrams[*]} 7+ letter anagrams found"
echo
echo ${Anagrams[0]}
echo ${Anagrams[1]}
exit $?
|
|
Examples of command substitution in shell scripts:
-
Example 11-8
-
Example 11-27
-
Example 9-16
-
Example 16-3
-
Example 16-22
-
Example 16-17
-
Example 16-54
-
Example 11-14
-
Example 11-11
-
Example 16-32
-
Example 20-8
-
Example A-16
-
Example 29-3
-
Example 16-47
-
Example 16-48
-
Example 16-49