📄 ch34_17.htm
字号:
<HTML><!--Distributed by F --><HEAD><TITLE>[Chapter 34] 34.17 Searching for Patterns Split Across Lines </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:47:27Z"><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_16.htm"TITLE="34.16 The Deliberate Scrivener "><LINKREL="next"HREF="ch34_18.htm"TITLE="34.18 Multiline Delete "></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_16.htm"TITLE="34.16 The Deliberate Scrivener "><IMGSRC="gifs/txtpreva.gif"SRC="gifs/txtpreva.gif"ALT="Previous: 34.16 The Deliberate Scrivener "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_18.htm"TITLE="34.18 Multiline Delete "><IMGSRC="gifs/txtnexta.gif"SRC="gifs/txtnexta.gif"ALT="Next: 34.18 Multiline Delete "BORDER="0"></A></TD></TR></TABLE> <HRALIGN="LEFT"WIDTH="515"TITLE="footer"></DIV><DIVCLASS="SECT1"><H2CLASS="sect1"><ACLASS="title"NAME="UPT-ART-0090">34.17 Searching for Patterns Split Across Lines </A></H2><PCLASS="para"><ACLASS="indexterm"NAME="AUTOID-39103"></A>[Article <ACLASS="xref"HREF="ch27_11.htm"TITLE="A Multiline Context grep Using sed ">27.11</A>introduced ascript called <ICLASS="filename">cgrep.sed</I>,a general-purpose, <ICLASS="filename">grep</I>-like program built with <ICLASS="filename">sed</I>.It allows you to look for one or more words that appear on one lineor across several lines.This article explains the <ICLASS="filename">sed</I> tricks thatare necessary to do this kind of thing.It gets into territory thatis essential for any advanced applications of this obscure yetwonderful editor.(Articles<ACLASS="xref"HREF="ch34_13.htm"TITLE="Hold Space: The Set-Aside Buffer ">34.13</A>through<ACLASS="xref"HREF="ch34_16.htm"TITLE="The Deliberate Scrivener ">34.16</A>have background information.) -JP]</P><PCLASS="para">Let's review the two examples from article<ACLASS="xref"HREF="ch27_11.htm"TITLE="A Multiline Context grep Using sed ">27.11</A>.The first command below finds all lines containing the word <EMCLASS="emphasis">system</EM>in the file <EMCLASS="emphasis">main.c</EM>, and shows 10 additional lines of context aboveand below each match.The second command finds all occurrences of the word "awk" where it isfollowed by the word "perl" somewhere within the next 3 lines:<ACLASS="indexterm"NAME="AUTOID-39117"></A></P><PCLASS="para"><BLOCKQUOTECLASS="screen"><PRECLASS="screen">cgrep -10 system main.ccgrep -3 "awk.*perl"</PRE></BLOCKQUOTE></P><PCLASS="para">Now the script, followed by an explanation of how it works:</P><PCLASS="para"><TABLECLASS="screen.co"BORDER="1"><TR><THVALIGN="TOP"><PRECLASS="calloutlist"> <ACLASS="co"HREF="ch44_06.htm"TITLE="44.6 Pattern Matching in case Statements ">case</A> <ACLASS="co"HREF="ch45_28.htm"TITLE="45.28 Quick Reference: expr ">expr</A> <ACLASS="co"HREF="ch45_12.htm"TITLE="45.12 Parameter Substitution ">${?}</A> <ACLASS="co"HREF="ch44_15.htm"TITLE="44.15 Handling Command-Line Arguments in Shell Scripts ">"$@"</A> </PRE></TH><TDVALIGN="TOP"><PRECLASS="screen">#!/bin/sh# cgrep - multiline context grep using sed# Usage: cgrep [-context] pattern [file...]n=3case $1 in -[1-9]*) n=`expr 1 - "$1"` shiftesacre=${1?}; shiftsed -n " 1b start : top \~$re~{ h; n; p; H; g b endif } N : start //{ =; p; } : endif $n,\$D b top" "$@"</PRE></TD></TR></TABLE></P><PCLASS="para">The <EMCLASS="emphasis">sed</EM> script is embedded in a bare-bones<SPANCLASS="link">shell wrapper (<ACLASS="linkend"HREF="ch44_14.htm"TITLE="Putting awk, sed, etc., Inside Shell Scripts ">44.14</A>)</SPAN>to parse out the initial arguments because, unlike <EMCLASS="emphasis">awk</EM> and<EMCLASS="emphasis">perl</EM>, <EMCLASS="emphasis">sed</EM> cannot directly access command-line parameters.If the first argument looks like a <EMCLASS="emphasis">-context</EM> option, variable<EMCLASS="emphasis">n</EM> is reset to one more than the number of lines specified, usinga little trick - the argument is treated as a negative number andsubtracted from <CODECLASS="literal">1</CODE>.The pattern argument is then stored in <CODECLASS="literal">$re</CODE>, with the<CODECLASS="literal">${1?}</CODE> syntax causing the shell to abort with an error messageif no pattern was given.Any remaining arguments are passed as filenames to the <EMCLASS="emphasis">sed</EM>command.</P><PCLASS="para">So that the <CODECLASS="literal">$re</CODE> and <CODECLASS="literal">$n</CODE> parameters can be embedded,the sed script is enclosed in<SPANCLASS="link">double quotes (<ACLASS="linkend"HREF="ch08_14.htm"TITLE="Bourne Shell Quoting ">8.14</A>)</SPAN>.We use the <EMCLASS="emphasis">-n</EM> option because we don't want to print out everyline by default, and because we need to use the <CODECLASS="literal">n</CODE> commandin the script without its side effect of outputting a line.</P><PCLASS="para">The <EMCLASS="emphasis">sed</EM> script itself looks rather unstructured (it was actuallydesigned using a flowchart), but the basic algorithm is easy enoughto understand.We keep a "window" of <EMCLASS="emphasis">n</EM> lines in the pattern spaceand scroll this window through the input stream.If an occurrence of the pattern comes into the window, the entirewindow is printed (providing <EMCLASS="emphasis">n</EM> lines of previous context), andeach subsequent line is printed until the pattern scrolls out of viewagain (providing <EMCLASS="emphasis">n</EM> lines of following context).The sed idiom <CODECLASS="literal">N;D</CODE> is used to advance the window, with the<CODECLASS="literal">D</CODE> not kicking in until the first <EMCLASS="emphasis">n</EM> lines of input havebeen accumulated.</P><PCLASS="para">The core of the script is basically an if-then-else constructthat decides if we are currently "in context."(The regular expression here is delimited by tilde (<CODECLASS="literal">~</CODE>)characters because tildes are less likely to occur in the user-suppliedpattern than slashes.)<BCLASS="emphasis.bold">If</B> we are still in context, <BCLASS="emphasis.bold">then</B> the next line ofinput is read and output, temporarily using the hold space tosave the window (and effectively doing an <CODECLASS="literal">N</CODE> in the process).<BCLASS="emphasis.bold">Else</B> we append the next input line (<CODECLASS="literal">N</CODE>) and search for thepattern again (an empty regular expression means to reuse thelast pattern).If it's now found, then the pattern must have just come into view - sowe print the current line number followed by the contents of thewindow.Subsequent iterations will take the "then" branch until the patternscrolls out of the window.</P><DIVCLASS="sect1info"><PCLASS="SECT1INFO">- <SPANCLASS="authorinitials">GU</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_16.htm"TITLE="34.16 The Deliberate Scrivener "><IMGSRC="gifs/txtpreva.gif"SRC="gifs/txtpreva.gif"ALT="Previous: 34.16 The Deliberate Scrivener "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_18.htm"TITLE="34.18 Multiline Delete "><IMGSRC="gifs/txtnexta.gif"SRC="gifs/txtnexta.gif"ALT="Next: 34.18 Multiline Delete "BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="172">34.16 The Deliberate Scrivener </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.18 Multiline Delete </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 + -