3.12. Command Substitution

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.

   1 script_name=`basename $0`
   2 echo "The name of this script is $script_name."

The output of commands can be used as arguments to another command, to set a variable, and even for generating the argument list in a "for" loop.

   1 rm `cat filename`
   2 # "filename" contains a list of files to delete.
   3 #
   4 # S. C. points out that "arg list too long" error might result.
   5 # Better is              xargs rm -- < filename 
   6 # ( -- covers those cases where "filename" begins with a "-" )
   7 
   8 textfile_listing=`ls *.txt`
   9 # Variable contains names of all *.txt files in current working directory.
  10 echo $textfile_listing
  11 
  12 textfile_listing2=$(ls *.txt)   # The alternative form of command substitution.
  13 echo $textfile_listing
  14 # Same result.
  15 
  16 # A possible problem with putting a list of files into a single string
  17 # is that a newline may creep in.
  18 #
  19 # A safer way to assign a list of files to a parameter is with an array.
  20 #      shopt -s nullglob    # If no match, filename expands to nothing.
  21 #      textfile_listing=( *.txt )
  22 #
  23 # Thanks, S.C.

Caution

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.

Caution

Word splitting resulting from command substitution may remove trailing newlines characters from the output of the reassigned command(s). This can cause unpleasant surprises.

   1 dir_listing=`ls -l`
   2 echo $dirlisting
   3 
   4 # Expecting a nicely ordered directory listing, such as:
   5 # -rw-rw-r--    1 bozo       30 May 13 17:15 1.txt
   6 # -rw-rw-r--    1 bozo       51 May 15 20:57 t2.sh
   7 # -rwxr-xr-x    1 bozo      217 Mar  5 21:13 wi.sh
   8 
   9 # However, what you get is:
  10 # total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo
  11 # bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh
  12 
  13 # The newlines disappeared.

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.

Note

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:

  1. Example 3-49

  2. Example 3-65

  3. Example 3-41

  4. Example 3-85

  5. Example 3-96

  6. Example 3-93

  7. Example 3-109

  8. Example 3-53

  9. Example 3-51

  10. Example 3-103

  11. Example 3-122

  12. Example A-11

  13. Example 3-156

  14. Example 3-107

  15. Example 3-108