Command
substitution reassigns the output of a command
[1]
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.
1 script_name=`basename $0`
2 echo "The name of this script is $script_name." |
1 rm `cat filename` # "filename" contains a list of files to delete.
2 #
3 # S. C. points out that "arg list too long" error might result.
4 # Better is xargs rm -- < filename
5 # ( -- covers those cases where "filename" begins with a "-" )
6
7 textfile_listing=`ls *.txt`
8 # Variable contains names of all *.txt files in current working directory.
9 echo $textfile_listing
10
11 textfile_listing2=$(ls *.txt) # The alternative form of command substitution.
12 echo $textfile_listing
13 # Same result.
14
15 # A possible problem with putting a list of files into a single string
16 # is that a newline may creep in.
17 #
18 # A safer way to assign a list of files to a parameter is with an array.
19 # shopt -s nullglob # If no match, filename expands to nothing.
20 # textfile_listing=( *.txt )
21 #
22 # Thanks, S.C. |
 | Command substitution may result in word splitting.
1 COMMAND `echo a b` # 2 args: a and b
2
3 COMMAND "`echo a b`" # 1 arg: "a b"
4
5 COMMAND `echo` # no arg
6
7 COMMAND "`echo`" # one empty arg
8
9
10 # Thanks, S.C. |
Even when there is no word splitting, command
substitution can remove trailing newlines.
1 # cd "`pwd`" # This should always work.
2 # However...
3
4 mkdir 'dir with trailing newline
5 '
6
7 cd 'dir with trailing newline
8 '
9
10 cd "`pwd`" # Error message:
11 # bash: cd: /tmp/file with trailing newline: No such file or directory
12
13 cd "$PWD" # Works fine.
14
15
16
17
18
19 old_tty_setting=$(stty -g) # Save old terminal setting.
20 echo "Hit a key "
21 stty -icanon -echo # Disable "canonical" mode for terminal.
22 # Also, disable *local* echo.
23 key=$(dd bs=1 count=1 2> /dev/null) # Using 'dd' to get a keypress.
24 stty "$old_tty_setting" # Restore old setting.
25 echo "You hit ${#key} key." # ${#variable} = number of characters in $variable
26 #
27 # Hit any key except RETURN, and the output is "You hit 1 key."
28 # Hit RETURN, and it's "You hit 0 key."
29 # The newline gets eaten in the command substitution.
30
31 Thanks, S.C. |
|
 | 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.
1 dir_listing=`ls -l`
2 echo $dir_listing # unquoted
3
4 # Expecting a nicely ordered directory listing.
5
6 # However, what you get is:
7 # total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo
8 # bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh
9
10 # The newlines disappeared.
11
12
13 echo "$dir_listing" # quoted
14 # -rw-rw-r-- 1 bozo 30 May 13 17:15 1.txt
15 # -rw-rw-r-- 1 bozo 51 May 15 20:57 t2.sh
16 # -rwxr-xr-x 1 bozo 217 Mar 5 21:13 wi.sh |
|
Command substitution even permits setting a variable to the
contents of a file, using either redirection or the cat command.
1 variable1=`<file1` # Set "variable1" to contents of "file1".
2 variable2=`cat file2` # Set "variable2" to contents of "file2".
3
4 # Be aware that the variables may contain embedded whitespace,
5 #+ or even (horrors), control characters. |
1 # Excerpts from system file, /etc/rc.d/rc.sysinit
2 #+ (on a Red Hat Linux installation)
3
4
5 if [ -f /fsckoptions ]; then
6 fsckoptions=`cat /fsckoptions`
7 ...
8 fi
9 #
10 #
11 if [ -e "/proc/ide/${disk[$device]}/media" ] ; then
12 hdmedia=`cat /proc/ide/${disk[$device]}/media`
13 ...
14 fi
15 #
16 #
17 if [ ! -n "`uname -r | grep -- "-"`" ]; then
18 ktag="`cat /proc/version`"
19 ...
20 fi
21 #
22 #
23 if [ $usb = "1" ]; then
24 sleep 5
25 mouseoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=02"`
26 kbdoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=01"`
27 ...
28 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 14-1. Stupid script tricks 1 #!/bin/bash
2 # stupid-script-tricks.sh: Don't try this at home, folks.
3
4
5 dangerous_variable=`cat /boot/vmlinuz` # The compressed Linux kernel itself.
6
7 echo "string-length of \$dangerous_variable = ${#dangerous_variable}"
8 # string-length of $dangerous_variable = 794151
9 # (Does not give same count as 'wc -c /boot/vmlinuz'.)
10
11 # echo "$dangerous_variable"
12 # Don't try this! It would hang the script.
13
14
15 # The document author is aware of no useful applications for
16 #+ setting a variable to the contents of a binary file.
17
18 exit 0 |
|
 | The $(COMMAND) form has
superseded backticks for command substitution.
1 output=$(sed -n /"$1"/p $file)
2 # From "grp.sh" example. |
|
Examples of command substitution in shell scripts:
Example 10-7
Example 10-24
Example 9-22
Example 12-2
Example 12-15
Example 12-12
Example 12-34
Example 10-12
Example 10-9
Example 12-24
Example 16-5
Example A-13
Example 28-1
Example 12-30
Example 12-31
Example 12-32