📄 ch45_31.htm
字号:
<HTML><!--Distributed by F --><HEAD><TITLE>[Chapter 45] 45.31 Nested Command Substitution </TITLE><METANAME="DC.title"CONTENT="UNIX Power Tools"><METANAME="DC.creator"CONTENT="Jerry Peek, Tim O'Reilly & Mike Loukides"><METANAME="DC.publisher"CONTENT="O'Reilly & Associates, Inc."><METANAME="DC.date"CONTENT="1998-08-04T21:55:09Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-260-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch45_01.htm"TITLE="45. Shell Programming for the Initiated"><LINKREL="prev"HREF="ch45_30.htm"TITLE="45.30 Grabbing Parts of a String "><LINKREL="next"HREF="ch45_32.htm"TITLE="45.32 A Better read Command: grabchars "></HEAD><BODYBGCOLOR="#FFFFFF"TEXT="#000000"><DIVCLASS="htmlnav"><H1><IMGSRC="gifs/smbanner.gif"ALT="UNIX Power Tools"USEMAP="#srchmap"BORDER="0"></H1><MAPNAME="srchmap"><AREASHAPE="RECT"COORDS="0,0,466,58"HREF="index.htm"ALT="UNIX Power Tools"><AREASHAPE="RECT"COORDS="467,0,514,18"HREF="jobjects/fsearch.htm"ALT="Search this book"></MAP><TABLEWIDTH="515"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="172"><ACLASS="SECT1"HREF="ch45_30.htm"TITLE="45.30 Grabbing Parts of a String "><IMGSRC="gifs/txtpreva.gif"SRC="gifs/txtpreva.gif"ALT="Previous: 45.30 Grabbing Parts of a String "BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="171"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1">Chapter 45<BR>Shell Programming for the Initiated</FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="172"><ACLASS="SECT1"HREF="ch45_32.htm"TITLE="45.32 A Better read Command: grabchars "><IMGSRC="gifs/txtnexta.gif"SRC="gifs/txtnexta.gif"ALT="Next: 45.32 A Better read Command: grabchars "BORDER="0"></A></TD></TR></TABLE> <HRALIGN="LEFT"WIDTH="515"TITLE="footer"></DIV><DIVCLASS="SECT1"><H2CLASS="sect1"><ACLASS="title"NAME="UPT-ART-9903">45.31 Nested Command Substitution </A></H2><PCLASS="para"><ACLASS="indexterm"NAME="AUTOID-54842"></A><ACLASS="indexterm"NAME="AUTOID-54845"></A>Article<ACLASS="xref"HREF="ch09_16.htm"TITLE="Command Substitution ">9.16</A>introduces command substitution with a pair of backquotes (<CODECLASS="literal">``</CODE>).Let's review.The shell runs a backquoted string as a command, then replaces thestring with its output.Sometimes - though not as often - you'll want to use the results fromone backquoted string as arguments to another command, itself alsoinside backquotes.To do that, you need to nest the backquotes, to tell the shell whichcommand (which set of backquotes) should be done first, with its outputgiven to the second command.This is tricky with backquotes; the Korn Shell introduced an easierway that you'll see below.Here's a simple example - the first command line uses nested backquotes,and the next two commands show its parts:[5]</P><BLOCKQUOTECLASS="footnote"><PCLASS="para">[5] True, this won't give the right answer after 1998.True, the Korn shell has built-in arithmetic.But this <EMCLASS="emphasis">is</EM> a simple example!</P></BLOCKQUOTE><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">$ <CODECLASS="userinput"><B>echo "Next year will be 19`expr \`date +%y\` + 1`."</B></CODE>Next year will be 1997.$ <CODECLASS="userinput"><B>date +%y</B></CODE>96$ <CODECLASS="userinput"><B>expr 96 + 1</B></CODE>97</PRE></BLOCKQUOTE></P><PCLASS="para">The command to run first has escaped backquotes (<CODECLASS="literal">\`\`</CODE>)around it.In the example above, that's the <CODECLASS="literal">date +%y</CODE> command.<CODECLASS="literal">date +%y</CODE> outputs the year - in this case, <CODECLASS="literal">96</CODE> - and thatvalue is passed to the <EMCLASS="emphasis">expr</EM> command.<EMCLASS="emphasis">expr</EM> adds 96 and 1 to get 97.Then that result (from the outer backquotes) is passed to <EMCLASS="emphasis">echo</EM>,on its command line, and <EMCLASS="emphasis">echo</EM> prints the message.</P><PCLASS="para">Why does the inner command, inside the escaped backquotes(<CODECLASS="literal">\`\`</CODE>), run first?It's because the backslash before the backquote<SPANCLASS="link">turns off the special meaning (<ACLASS="linkend"HREF="ch08_14.htm"TITLE="Bourne Shell Quoting ">8.14</A>)</SPAN>of the backquote.So, when the shell first<SPANCLASS="link">evaluates the command line (<ACLASS="linkend"HREF="ch08_05.htm"TITLE="Command-Line Evaluation ">8.5</A>)</SPAN>,which backquotes does it see?It sees the unescaped backquotes, the ones around the <CODECLASS="literal">expr</CODE>command, and the shell runs the command:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">expr `date +%y` + 1</PRE></BLOCKQUOTE></P><PCLASS="para">But when the shell evaluates that command line, it sees the backquotesin it (now unescaped) and runs <EMCLASS="emphasis">that</EM> command-<CODECLASS="literal">date +%y</CODE>.The <CODECLASS="literal">date +%y</CODE> command outputs <CODECLASS="literal">96</CODE>.Next, the shell can finish the command <CODECLASS="literal">expr 96 + 1</CODE>.It outputs 97.Then the <EMCLASS="emphasis">echo</EM> command can print its message.</P><PCLASS="para"><ACLASS="indexterm"NAME="AUTOID-54882"></A>Whew.If you use the Korn shell or <EMCLASS="emphasis">bash</EM>, there's an easier way:the <CODECLASS="literal">$(</CODE><CODECLASS="replaceable"><I>command</I></CODE><CODECLASS="literal">)</CODE> operators.Use <CODECLASS="literal">$(</CODE> before the command, where you would use an openingbackquote.Put the <CODECLASS="literal">)</CODE> after the command, in place of a closing backquote.You don't have to escape these operators when you nest them.</P><PCLASS="para">Here's the previous example with <CODECLASS="literal">$( )</CODE>, then a morereal-life example:</P><PCLASS="para"><TABLECLASS="screen.co"BORDER="1"><TR><THVALIGN="TOP"><PRECLASS="calloutlist"> <ACLASS="co"HREF="ch45_21.htm"TITLE="45.21 n>&m: Swap Standard Output and Standard Error ">2>&1</A> </PRE></TH><TDVALIGN="TOP"><PRECLASS="screen">$ <CODECLASS="userinput"><B>echo "Next year will be 19$(expr $(date +%y) + 1)."</B></CODE>Next year will be 1997.<ACLASS="indexterm"NAME="AUTOID-54896"></A>$ <CODECLASS="userinput"><B>tarout=$(tar cf /dev/rst1 $(find . -type f -mtime -1 -print) 2>&1)</B></CODE> <ICLASS="lineannotation">time passes...</I>$ echo "$tarout"tar: ./files/145923: Permission denied</PRE></TD></TR></TABLE></P><PCLASS="para"><ACLASS="indexterm"NAME="AUTOID-54903"></A>The inner command - in this case, the<SPANCLASS="link"><EMCLASS="emphasis">find</EM> (<ACLASS="linkend"HREF="ch17_01.htm#UPT-ART-7410"TITLE="The find Command Is Great; The Problem Is Finding How to Use It">17.1</A>)</SPAN>-is run first.Its output, a list of filenames, is put on the command line of the<SPANCLASS="link"><EMCLASS="emphasis">tar</EM> (<ACLASS="linkend"HREF="ch20_01.htm#UPT-ART-8024"TITLE="tar in a Nutshell ">20.1</A>)</SPAN>command.Finally, the output of <EMCLASS="emphasis">tar</EM> (in this case, an error message)is stored in the <EMCLASS="emphasis">tarout</EM> shell variable.</P><PCLASS="para">Beginners (and some long-time programmers too) might argue that youshould never nest command substitution because it's too confusing.I think there are times nesting is clearer.It's more compact and doesn't need temporary storage.And it's not that hard to understand once you see what's happening.There's another nice example in article<ACLASS="xref"HREF="ch38_13.htm"TITLE="Interactively Kill Processes Matching a Pattern ">38.13</A>.</P><DIVCLASS="sect1info"><PCLASS="SECT1INFO">- <SPANCLASS="authorinitials">JP</SPAN></P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="515"TITLE="footer"><TABLEWIDTH="515"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="172"><ACLASS="SECT1"HREF="ch45_30.htm"TITLE="45.30 Grabbing Parts of a String "><IMGSRC="gifs/txtpreva.gif"SRC="gifs/txtpreva.gif"ALT="Previous: 45.30 Grabbing Parts of a String "BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="171"><ACLASS="book"HREF="index.htm"TITLE="UNIX Power Tools"><IMGSRC="gifs/txthome.gif"SRC="gifs/txthome.gif"ALT="UNIX Power Tools"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="172"><ACLASS="SECT1"HREF="ch45_32.htm"TITLE="45.32 A Better read Command: grabchars "><IMGSRC="gifs/txtnexta.gif"SRC="gifs/txtnexta.gif"ALT="Next: 45.32 A Better read Command: grabchars "BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="172">45.30 Grabbing Parts of a String </TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="171"><ACLASS="index"HREF="index/idx_0.htm"TITLE="Book Index"><IMGSRC="gifs/index.gif"SRC="gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="172">45.32 A Better read Command: grabchars </TD></TR></TABLE><HRALIGN="LEFT"WIDTH="515"TITLE="footer"><IMGSRC="gifs/smnavbar.gif"SRC="gifs/smnavbar.gif"USEMAP="#map"BORDER="0"ALT="The UNIX CD Bookshelf Navigation"><MAPNAME="map"><AREASHAPE="RECT"COORDS="0,0,73,21"HREF="../index.htm"ALT="The UNIX CD Bookshelf"><AREASHAPE="RECT"COORDS="74,0,163,21"HREF="index.htm"ALT="UNIX Power Tools"><AREASHAPE="RECT"COORDS="164,0,257,21"HREF="../unixnut/index.htm"ALT="UNIX in a Nutshell"><AREASHAPE="RECT"COORDS="258,0,321,21"HREF="../vi/index.htm"ALT="Learning the vi Editor"><AREASHAPE="RECT"COORDS="322,0,378,21"HREF="../sedawk/index.htm"ALT="sed & awk"><AREASHAPE="RECT"COORDS="379,0,438,21"HREF="../ksh/index.htm"ALT="Learning the Korn Shell"><AREASHAPE="RECT"COORDS="439,0,514,21"HREF="../lrnunix/index.htm"ALT="Learning the UNIX Operating System"></MAP></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -