⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch34_15.htm

📁 the unix power tools
💻 HTM
字号:
<HTML><!--Distributed by F --><HEAD><TITLE>[Chapter 34] 34.15 Making Edits Across Line Boundaries </TITLE><METANAME="DC.title"CONTENT="UNIX Power Tools"><METANAME="DC.creator"CONTENT="Jerry Peek, Tim O'Reilly &amp; Mike Loukides"><METANAME="DC.publisher"CONTENT="O'Reilly &amp; Associates, Inc."><METANAME="DC.date"CONTENT="1998-08-04T21:47:23Z"><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="ch34_01.htm"TITLE="34. The sed Stream Editor"><LINKREL="prev"HREF="ch34_14.htm"TITLE="34.14 Transforming Part of a Line "><LINKREL="next"HREF="ch34_16.htm"TITLE="34.16 The Deliberate Scrivener "></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="ch34_14.htm"TITLE="34.14 Transforming Part of a Line "><IMGSRC="gifs/txtpreva.gif"SRC="gifs/txtpreva.gif"ALT="Previous: 34.14 Transforming Part of a Line "BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="171"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1">Chapter 34<BR>The sed Stream Editor</FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="172"><ACLASS="SECT1"HREF="ch34_16.htm"TITLE="34.16 The Deliberate Scrivener "><IMGSRC="gifs/txtnexta.gif"SRC="gifs/txtnexta.gif"ALT="Next: 34.16 The Deliberate Scrivener "BORDER="0"></A></TD></TR></TABLE>&nbsp;<HRALIGN="LEFT"WIDTH="515"TITLE="footer"></DIV><DIVCLASS="SECT1"><H2CLASS="sect1"><ACLASS="title"NAME="UPT-ART-0089">34.15 Making Edits Across Line Boundaries </A></H2><PCLASS="para"><ACLASS="indexterm"NAME="UPT-ART-89-IX-SED-PATTERN-SPACE"></A><ACLASS="indexterm"NAME="AUTOID-38964"></A>Most programs that use<SPANCLASS="link">regular expressions (<ACLASS="linkend"HREF="ch26_04.htm"TITLE="Using Metacharacters in Regular Expressions ">26.4</A>)</SPAN>are ableto match a pattern only on a single line of input. This makesit difficult to find or change a phrase, for instance, because it can startnear the end of one line and finish near the beginning of the nextline. Other patterns might be significant only when repeatedon multiple lines.</P><PCLASS="para"><EMCLASS="emphasis">sed</EM> has the ability to load more than one line into the patternspace.This allows you to match (and change) patterns that extend over multiple lines.In this article, we show how tocreate a multiline pattern space and manipulateits contents. </P><PCLASS="para">The multiline Next command, <EMCLASS="emphasis">N</EM>, creates a multiline pattern spaceby reading a new line of input and appending it to thecontents of the pattern space.The original contents of the pattern space and the new input lineare separated by a newline.The embedded newline character can be matched in patternsby the escape sequence <CODECLASS="literal">\n</CODE>.In a multiline pattern space, only the metacharacter <CODECLASS="literal">^</CODE> matches the newline at the beginning of the pattern spaceand <CODECLASS="literal">$</CODE> matches the newline at the end. After the Next command is executed, control is then passed to subsequent commands in the script.</P><PCLASS="para">The Next command differs from the next command, <EMCLASS="emphasis">n</EM>,which outputs the contents of the pattern spaceand then reads a new line of input. The next command doesnot create a multiline pattern space. </P><PCLASS="para">For our first example, let's suppose that we wanted tochange &quot;Owner and Operator Guide&quot; to &quot;Installation Guide&quot;but we found that it appears in the file on two lines,splitting between <CODECLASS="literal">Operator</CODE> and <CODECLASS="literal">Guide</CODE>.For instance, here are a few lines of sample text:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">Consult Section 3.1 in the Owner and OperatorGuide for a description of the tape drivesavailable on your system.</PRE></BLOCKQUOTE></P><PCLASS="para">The following script looks for <CODECLASS="literal">Operator</CODE> at the end of a line, reads the next line of input, and then makesthe replacement:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">/Operator$/{    N    s/Owner and Operator\nGuide/Installation Guide/}</PRE></BLOCKQUOTE></P><PCLASS="para">&#13;In this example, we know where the two lines split and where to specify the embedded newline.When the script is run on the sample file, it producesthe two lines of output, one of which combinesthe first and second lines and is too longto show here.This happens because the substitute command matchesthe embedded newline but does not replace it. Unfortunately, you cannot use <CODECLASS="literal">\n</CODE> to insert a newlinein the replacement string.You must either use the backslashto escape the newline, as follows:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">s/Owner and Operator\nGuide /Installation Guide\/</PRE></BLOCKQUOTE></P><PCLASS="para">or use the<SPANCLASS="link"><CODECLASS="literal">\(</CODE>..<CODECLASS="literal">\)</CODE> operators (<ACLASS="linkend"HREF="ch34_10.htm"TITLE="Referencing Portions of a Search String ">34.10</A>)</SPAN>to keep the newline:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">s/Owner and Operator\(\n\)Guide /Installation Guide\1/</PRE></BLOCKQUOTE></P><PCLASS="para">This command restores the newline after <CODECLASS="literal">Installation Guide</CODE>.It is also necessary to match a blank space following <CODECLASS="literal">Guide</CODE>so the new line won't begin with a space. Now we can show the output: </P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">Consult Section 3.1 in the Installation Guide for a description of the tape drivesavailable on your system.</PRE></BLOCKQUOTE></P><PCLASS="para">Remember, you don't have to replace the newline, but if youdon't, it can make for some long lines.</P><PCLASS="para">What if there are other occurrences of &quot;Owner and Operator Guide&quot; that break overmultiple lines in different places? You could change the address to match <CODECLASS="literal">Owner</CODE>, the firstword in the pattern instead of the last, and then modify the regular expression to look for a space or a newlinebetween words, as shown below:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">/Owner/{Ns/Owner *\n*and *\n*Operator *\n*Guide/Installation Guide/}</PRE></BLOCKQUOTE></P><PCLASS="para">The asterisk (<CODECLASS="literal">*</CODE>) indicates that the space or newline is optional.This seems like hard work though, and indeed there is a moregeneral way. We can read the newlineinto the pattern space and thenuse a substitute command to remove the embedded newline, whereverit is: </P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">s/Owner and Operator Guide/Installation Guide//Owner/{Ns/ *\n/ /s/Owner and Operator Guide */Installation Guide\/}</PRE></BLOCKQUOTE></P><PCLASS="para">The first line of the script matches <CODECLASS="literal">Owner and Operator Guide</CODE> when it appearson a line by itself. (See the discussion at the end of the article aboutwhy this is necessary.)If we match the string<CODECLASS="literal">Owner</CODE>, we read the next line into the pattern space and replace theembedded newline with a space. Then we attempt to match the wholepattern and make the replacement followed by a newline.This script will match <CODECLASS="literal">Owner and OperatorGuide</CODE> regardlessof how it is broken across two lines.Here's our expanded test file:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">Consult Section 3.1 in the Owner and OperatorGuide for a description of the tape drivesavailable on your system.Look in the Owner and Operator Guide shipped with your system.Two manuals are provided, including the Owner andOperator Guide and the User Guide.The Owner and Operator Guide is shipped with your system.</PRE></BLOCKQUOTE></P><PCLASS="para">Running the above script on the sample file producesthe following result:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">% <CODECLASS="userinput"><B>sed -f sedscr sample</B></CODE>Consult Section 3.1 in the Installation Guidefor a description of the tape drivesavailable on your system.Look in the Installation Guide shipped with your system.Two manuals are provided, including the Installation Guideand the User Guide.The Installation Guide is shipped with your system.</PRE></BLOCKQUOTE></P><PCLASS="para">&#13;In this sample script, itmight seem redundant to have two substitute commands thatmatch the pattern. The first command matches it when thepattern is found already on one line, and the second matchesthe pattern after two lines have been read into the pattern space. Why the first command is necessary is perhaps best demonstratedby removing that command from the script and running it onthe sample file:</P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">% <CODECLASS="userinput"><B>sed -f sedscr2 sample</B></CODE>Consult Section 3.1 in the Installation Guidefor a description of the tape drivesavailable on your system.Look in the Installation Guideshipped with your system.Two manuals are provided, including the Installation Guideand the User Guide.</PRE></BLOCKQUOTE></P><PCLASS="para">Do you see the two problems?The most obvious problem is that the last linedid not print. The last line matches <CODECLASS="literal">Owner</CODE>, andwhen <EMCLASS="emphasis">N</EM> is executed, there is not another inputline to read, so <EMCLASS="emphasis">sed</EM> quits.It does not even output the line.If this is the normalbehavior,the Next command should be used as followsto be safe: </P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">$!N</PRE></BLOCKQUOTE></P><PCLASS="para">It excludes the last line (<CODECLASS="literal">$</CODE>) from the Next command.As it is in our script, by matching <CODECLASS="literal">Owner and OperatorGuide</CODE> on the last line, we avoid matching <CODECLASS="literal">Owner</CODE>and applying the <EMCLASS="emphasis">N</EM> command. However, if the word <CODECLASS="literal">Owner</CODE>appeared on the last line we'd have the same problemunless we implement the <CODECLASS="literal">$!N</CODE> syntax. </P><PCLASS="para">The second problem is a little less conspicuous. It hasto do with the occurrence of <CODECLASS="literal">Owner and OperatorGuide</CODE> in the second paragraph. In the input file,it is found on a line by itself: </P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">Look in the Owner and Operator Guide shipped with your system.</PRE></BLOCKQUOTE></P><PCLASS="para">In the output shown above, the blank line following<CODECLASS="literal">shipped with your system</CODE> is missing. The reason forthis is that this line matches <CODECLASS="literal">Owner</CODE> and the nextline, a blank line, is appended to the pattern space.The substitute command removes the embedded newline, andthe blank line has in effect vanished. (If the linewere not blank, the newline would still be removedbut the text would  appear on the same line with<CODECLASS="literal">shipped with your system</CODE>.) The bestsolution seems to be to avoid reading the next linewhen the pattern can be matched on one line.So, that is why the first instruction attempts to match the casewhere the string appears all on one line.<ACLASS="indexterm"NAME="AUTOID-39045"></A></P><DIVCLASS="sect1info"><PCLASS="SECT1INFO">- <SPANCLASS="authorinitials">DD</SPAN> <SPANCLASS="bibliomisc">from O'Reilly &amp; Associates' <CITECLASS="citetitle">sed &amp; awk</CITE>, Chapter 6</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="ch34_14.htm"TITLE="34.14 Transforming Part of a Line "><IMGSRC="gifs/txtpreva.gif"SRC="gifs/txtpreva.gif"ALT="Previous: 34.14 Transforming Part of a 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="ch34_16.htm"TITLE="34.16 The Deliberate Scrivener "><IMGSRC="gifs/txtnexta.gif"SRC="gifs/txtnexta.gif"ALT="Next: 34.16 The Deliberate Scrivener "BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="172">34.14 Transforming Part of a 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">34.16 The Deliberate Scrivener </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 &amp; 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 + -