📄 commandsub.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><HTML><HEAD><TITLE>Command Substitution</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+"><LINKREL="HOME"TITLE="Advanced Bash-Scripting Guide"HREF="index.html"><LINKREL="UP"TITLE="Beyond the Basics"HREF="part3.html"><LINKREL="PREVIOUS"TITLE="Testing and Branching"HREF="testbranch.html"><LINKREL="NEXT"TITLE="Arithmetic Expansion"HREF="arithexp.html"><METAHTTP-EQUIV="Content-Style-Type"CONTENT="text/css"><LINKREL="stylesheet"HREF="common/kde-common.css"TYPE="text/css"><METAHTTP-EQUIV="Content-Type"CONTENT="text/html; charset=iso-8859-1"><METAHTTP-EQUIV="Content-Language"CONTENT="en"><LINKREL="stylesheet"HREF="common/kde-localised.css"TYPE="text/css"TITLE="KDE-English"><LINKREL="stylesheet"HREF="common/kde-default.css"TYPE="text/css"TITLE="KDE-Default"></HEAD><BODYCLASS="CHAPTER"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#AA0000"VLINK="#AA0055"ALINK="#AA0000"STYLE="font-family: sans-serif;"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="testbranch.html"ACCESSKEY="P">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom"></TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="arithexp.html"ACCESSKEY="N">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="CHAPTER"><H1><ANAME="COMMANDSUB"></A>Chapter 11. Command Substitution</H1><P> <ANAME="COMMANDSUBREF"></A><BCLASS="COMMAND">Command substitution</B> reassigns the output of a command <ANAME="AEN6415"HREF="#FTN.AEN6415">[1]</A> or even multiple commands; it literally plugs the command output into another context. <ANAME="AEN6421"HREF="#FTN.AEN6421">[2]</A> </P><P><ANAME="BACKQUOTESREF"></A>The classic form of command substitution uses <ICLASS="FIRSTTERM">backquotes</I> (`...`). Commands within backquotes (backticks) generate command line text. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 script_name=`basename $0` 2 echo "The name of this script is $script_name."</PRE></TD></TR></TABLE></P><DIVCLASS="FORMALPARA"><P><B>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 <AHREF="loops.html#FORLOOPREF1">for</A> loop. </B></P></DIV><P> <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 rm `cat filename` # <SPANCLASS="QUOTE">"filename"</SPAN> 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 <SPANCLASS="QUOTE">"filename"</SPAN> begins with a <SPANCLASS="QUOTE">"-"</SPAN> ) 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_listing2 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.</PRE></TD></TR></TABLE> </P><DIVCLASS="NOTE"><TABLECLASS="NOTE"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/note.png"HSPACE="5"ALT="Note"></TD><TDALIGN="LEFT"VALIGN="TOP"><P><ANAME="CSSUBSH"></A>Command substitution invokes a <AHREF="subshells.html#SUBSHELLSREF">subshell</A>.</P></TD></TR></TABLE></DIV><DIVCLASS="CAUTION"><TABLECLASS="CAUTION"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/caution.png"HSPACE="5"ALT="Caution"></TD><TDALIGN="LEFT"VALIGN="TOP"><P><ANAME="CSWS"></A>Command substitution may result in word splitting. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 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.</PRE></TD></TR></TABLE></P><P><ANAME="CSTRNL"></A></P><P>Even when there is no word splitting, command substitution can remove trailing newlines. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 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.</PRE></TD></TR></TABLE> </P></TD></TR></TABLE></DIV><DIVCLASS="CAUTION"><TABLECLASS="CAUTION"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/caution.png"HSPACE="5"ALT="Caution"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>Using <BCLASS="COMMAND">echo</B> to output an <ICLASS="FIRSTTERM">unquoted</I> variable set with command substitution removes trailing newlines characters from the output of the reassigned command(s). This can cause unpleasant surprises. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 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</PRE></TD></TR></TABLE> </P></TD></TR></TABLE></DIV><P>Command substitution even permits setting a variable to the contents of a file, using either <AHREF="io-redirection.html#IOREDIRREF">redirection</A> or the <AHREF="external.html#CATREF">cat</A> command.</P><P> <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 variable1=`<file1` # Set "variable1" to contents of "file1". 2 variable2=`cat file2` # Set "variable2" to contents of "file2". 3 # This, however, forks a new process, 4 #+ so the line of code executes slower than the above version. 5 6 # Note: 7 # The variables may contain embedded whitespace, 8 #+ or even (horrors), control characters.</PRE></TD></TR></TABLE> </P><P> <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 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</PRE></TD></TR></TABLE> </P><DIVCLASS="CAUTION"><TABLECLASS="CAUTION"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/caution.png"HSPACE="5"ALT="Caution"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>Do not set a variable to the contents of a <SPANCLASS="emphasis"><ICLASS="EMPHASIS">long</I></SPAN> text file unless you have a very good reason for doing so. Do not set a variable to the contents of a <ICLASS="FIRSTTERM">binary</I> file, even as a joke.</P><DIVCLASS="EXAMPLE"><HR><ANAME="STUPSCR"></A><P><B>Example 11-1. Stupid script tricks</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # stupid-script-tricks.sh: Don't try this at home, folks. 3 # From "Stupid Script Tricks," Volume I. 4 5 6 dangerous_variable=`cat /boot/vmlinuz` # The compressed Linux kernel itself. 7 8 echo "string-length of \$dangerous_variable = ${#dangerous_variable}" 9 # string-length of $dangerous_variable = 794151 10 # (Does not give same count as 'wc -c /boot/vmlinuz'.) 11 12 # echo "$dangerous_variable" 13 # Don't try this! It would hang the script. 14 15 16 # The document author is aware of no useful applications for 17 #+ setting a variable to the contents of a binary file. 18 19 exit 0</PRE></TD></TR></TABLE><HR></DIV><P>Notice that a <ICLASS="FIRSTTERM">buffer overrun</I> does not occur. This is one instance where an interpreted language, such as Bash, provides more protection from programmer mistakes than a compiled language.</P></TD></TR></TABLE></DIV><P><ANAME="CSVL"></A></P><P>Command substitution permits setting a variable to the output of a <AHREF="loops.html#FORLOOPREF1">loop</A>. The key to this is grabbing the output of an <AHREF="internal.html#ECHOREF">echo</A> command within the loop.</P><DIVCLASS="EXAMPLE"><HR><ANAME="CSUBLOOP"></A><P><B>Example 11-2. Generating a variable from a loop</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # csubloop.sh: Setting a variable to the output of a loop. 3 4 variable1=`for i in 1 2 3 4 5 5 do 6 echo -n "$i" # The 'echo' command is critical 7 done` #+ to command substitution here. 8 9 echo "variable1 = $variable1" # variable1 = 12345 10 11 12 i=0 13 variable2=`while [ "$i" -lt 10 ] 14 do 15 echo -n "$i" # Again, the necessary 'echo'. 16 let "i += 1" # Increment. 17 done` 18 19 echo "variable2 = $variable2" # variable2 = 0123456789 20 21 # Demonstrates that it's possible to embed a loop 22 #+ within a variable declaration. 23 24 exit 0</PRE></TD></TR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -