📄 ch45_23.htm
字号:
<HTML><!--Distributed by F --><HEAD><TITLE>[Chapter 45] 45.23 The Ins and Outs of Redirected I/O Loops </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:54:52Z"><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_22.htm"TITLE="45.22 Handling Files Line-by-Line "><LINKREL="next"HREF="ch45_24.htm"TITLE="45.24 A Shell Can Read a Script from its Standard Input, But..."></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_22.htm"TITLE="45.22 Handling Files Line-by-Line "><IMGSRC="gifs/txtpreva.gif"SRC="gifs/txtpreva.gif"ALT="Previous: 45.22 Handling Files Line-by-Line "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_24.htm"TITLE="45.24 A Shell Can Read a Script from its Standard Input, But..."><IMGSRC="gifs/txtnexta.gif"SRC="gifs/txtnexta.gif"ALT="Next: 45.24 A Shell Can Read a Script from its Standard Input, But..."BORDER="0"></A></TD></TR></TABLE> <HRALIGN="LEFT"WIDTH="515"TITLE="footer"></DIV><DIVCLASS="SECT1"><H2CLASS="sect1"><ACLASS="title"NAME="UPT-ART-7928">45.23 The Ins and Outs of Redirected I/O Loops </A></H2><PCLASS="para"><ACLASS="indexterm"NAME="AUTOID-54021"></A><ACLASS="indexterm"NAME="AUTOID-54023"></A><ACLASS="indexterm"NAME="AUTOID-54026"></A><ACLASS="indexterm"NAME="AUTOID-54029"></A>The Bourne shell usually runs<SPANCLASS="link">a loop with redirected input or output (<ACLASS="linkend"HREF="ch45_22.htm"TITLE="Handling Files Line-by-Line ">45.22</A>)</SPAN>in a<SPANCLASS="link">subshell (<ACLASS="linkend"HREF="ch38_04.htm"TITLE="Subshells ">38.4</A>)</SPAN>.For the <EMCLASS="emphasis">formprog</EM> script in article<ACLASS="xref"HREF="ch45_22.htm"TITLE="Handling Files Line-by-Line ">45.22</A>,this means, among other things, that:</P><ULCLASS="itemizedlist"><LICLASS="listitem"><PCLASS="para"><ACLASS="indexterm"NAME="AUTOID-54039"></A>Any command inside the loop that reads its standard input willread from the pipe or file redirected to the loop's standard input.That's something you have to pay attention to, because the only command that should read from the file is usually the <EMCLASS="emphasis">read</EM> command at the topof the loop.The inputs of other commands inside the loop - like commands that readfrom the terminal - have to be redirected to read from somewhere otherthan the loop's standard input.</P></LI><LICLASS="listitem"><PCLASS="para"><ACLASS="indexterm"NAME="AUTOID-54045"></A><ACLASS="indexterm"NAME="AUTOID-54048"></A>In many Bourne shells, if you use the<SPANCLASS="link"><EMCLASS="emphasis">exit</EM> (<ACLASS="linkend"HREF="ch38_04.htm"TITLE="Subshells ">38.4</A>)</SPAN>command inside aredirected loop, that will only terminate the subshell that's runningthe loop; it will <EMCLASS="emphasis">not</EM> terminate thescript.It's hard to call this a "feature"; I'd call it a bug.The script in article<ACLASS="xref"HREF="ch45_22.htm"TITLE="Handling Files Line-by-Line ">45.22</A>has a workaround for this; see the next paragraph.Later versions of Bourne-like shells have fixed this problem, more or less,but the fix below should work in all Bourne shells.</P></LI><LICLASS="listitem"><PCLASS="para"><ACLASS="indexterm"NAME="AUTOID-54057"></A><ACLASS="indexterm"NAME="AUTOID-54060"></A><ACLASS="indexterm"NAME="AUTOID-54063"></A>If there's any error inside the loop that should terminate the script,an error message is written to file descriptor 2.File descriptor 2 is redirected to an error-holding file at the subshell(loop) output.A <EMCLASS="emphasis">break</EM> command can end the loop right away.After the loop ends, if the error file has anything in it, that meansthere was an error - if there are more commands to run, the script canterminate before running them.</P></LI><LICLASS="listitem"><PCLASS="para"><ACLASS="indexterm"NAME="AUTOID-54069"></A><ACLASS="indexterm"NAME="AUTOID-54072"></A>You can test the<SPANCLASS="link">exit status (<ACLASS="linkend"HREF="ch44_07.htm"TITLE="Exit Status of UNIX Processes ">44.7</A>)</SPAN>of the redirected-I/O loop.To end the loop, use a command like <CODECLASS="literal">exit 0</CODE>, <CODECLASS="literal">exit 2</CODE>,and so on.Just after the <CODECLASS="literal">done</CODE> command outside the loop, use<SPANCLASS="link"><CODECLASS="literal">case $?</CODE> (<ACLASS="linkend"HREF="ch44_05.htm"TITLE="Test String Values with Bourne Shell case ">44.5</A>)</SPAN>to test the loop's status.For instance, a 0 status might mean the loop worked fine, a 1 couldsignal one kind of error, a 2 status a different error, and so on.</P></LI><LICLASS="listitem"><PCLASS="para"><ACLASS="indexterm"NAME="AUTOID-54083"></A><ACLASS="indexterm"NAME="AUTOID-54086"></A>If you change the value of any shell or environment variables inside theloop, their values outside the loop (after the <EMCLASS="emphasis">done</EM> command atthe end of the loop) will not be changed.Here's the usual fix for that problem.You use another file descriptor, like file descriptor 6,and write variable-settingcommands to it.You redirect that file descriptor to a temporary file.Then, use the shell's<SPANCLASS="link">dot command (<CODECLASS="literal">.</CODE>) (<ACLASS="linkend"HREF="ch44_23.htm"TITLE="Reading Files with the . and source Commands ">44.23</A>)</SPAN>to read the temporary file into the shell outside the loop.For example, to get the value of a variable named <EMCLASS="emphasis">varname</EM> outside theloop:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen"><ACLASS="indexterm"NAME="AUTOID-54095"></A>while whateverdo ... echo "varname='value'" 1>&6 ...done 6> var_set_file. var_set_file</PRE></BLOCKQUOTE></P></LI></UL><PCLASS="para">Greg Ubben sent me two other ways that he prefers.The first one depends on having a <EMCLASS="emphasis">read</EM> that accepts redirectionon its command line, which most do these days.The second works when you can put the usage in the same scope (withinthe<SPANCLASS="link">curly braces (<ACLASS="linkend"HREF="ch13_08.htm"TITLE="Using {list} to Group Bourne Shell Commands ">13.8</A>)</SPAN>)as the redirection:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">exec 3< file {while read line <&3 while read linedo do var=value var=valuedone doneexec 3<&- echo "var = $var"echo "var = $var" } < file</PRE></BLOCKQUOTE></P><PCLASS="para">Putting the loop inside a function and redirecting into the functionalso seems to avoid the subshell problem.But don't take my (our) word for it:test it on the shell you'll be using.<ACLASS="indexterm"NAME="AUTOID-54104"></A><ACLASS="indexterm"NAME="AUTOID-54105"></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_22.htm"TITLE="45.22 Handling Files Line-by-Line "><IMGSRC="gifs/txtpreva.gif"SRC="gifs/txtpreva.gif"ALT="Previous: 45.22 Handling Files Line-by-Line "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_24.htm"TITLE="45.24 A Shell Can Read a Script from its Standard Input, But..."><IMGSRC="gifs/txtnexta.gif"SRC="gifs/txtnexta.gif"ALT="Next: 45.24 A Shell Can Read a Script from its Standard Input, But..."BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="172">45.22 Handling Files Line-by-Line </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.24 A Shell Can Read a Script from its Standard Input, But...</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 + -