使用AWK从目标正则拨号正向输出文件部分



这是使用awk/find到输出结果和文件名的扩展,我在其中找到了如何使用awk输出文件名,以及由start和start and tough结束言论。

所以,如果我有一个文件 filethree.txt 带有目录

XXX >>
 xxx one
 xxx two
 xxx three
<<
ZZZ >>
 zzz one
 zzz two
 zzz three
<<

然后此命令:

awk '/XXX/,/<</{print a[FILENAME]?$0:FILENAME RS $0;a[FILENAME]++}' *.txt

将输出

/d/Temp/temp/fileTwo.txt
XXX >>
 xxx one
 xxx two
 xxx three
<<

我喜欢它,每天都在使用它,但是我想进一步扩展它,但还没有弄清楚如何。本质上,我想说"在y和z之间搜索x,输出y之间的所有界线(以及列(包括线)到z"。

所以,我想搜索" xxx二",并从">>"开始,并以"&lt;&lt;"以">>"开始。 - 即它的输出与上述完全相同。


更新:2014年1月31日,星期五,下午03:53:29

显示 @endoro建议的结果,该建议无法完全正确输出。命令:

awk '/xxx one/{f=7};/>>/{delete(s)};{s[++i]=$0};/<</&&f {print FILENAME;for (j in s) print s[j];f=0}' *.txt

输出:

fileThree.txt
 xxx three
<<
XXX >>
 xxx one
 xxx two
fileTwo.txt
XXX >>
 xxx one
 xxx two
 xxx three
<<

更新:2014年2月4日,星期日

回应 @edmorton的答案,这些文件只是示例,一般格式是"记录"以任何以">>"结尾的行开始,并以任何只包含的行结尾"&lt;&lt;&lt;"。这意味着记录可以包含空白行。


更新:2014年2月3日,星期一,上午11:49:22 AM

在审查 @edmorton的答案时,我设计了以这种方式使用脚本的解决方案:

# Set these based on input arguments.
ignoreCase=
searchTerm=
directory=
# Then do the search
gawk -v RS='n<<n+' "BEGIN{IGNORECASE=$ignoreCase} /${searchTerm}/{print FILENAME ORS $0 ORS "<<"}" "${directory}"/*.txt | less -I -p "$searchTerm"

给定发布的输入格式,获得awk的输出的方法是:

awk -v RS= '/xxx two/{print FILENAME ORS $0}' file

请参阅:

$ cat file
XXX >>
 xxx one
 xxx two
 xxx three
<<
ZZZ >>
 zzz one
 zzz two
 zzz three
<<
$
$ awk -v RS= '/xxx two/{print FILENAME ORS $0}' file
file
XXX >>
 xxx one
 xxx two
 xxx three
<<

另外,给定更新的问题中的信息,即记录可以包含空白行,使用GNU Awk用于多char rs:

$ gawk -v RS='n<<n+' '/xxx two/{print FILENAME ORS $0 ORS "<<"}' file
file
XXX >>
 xxx one
 xxx two
 xxx three
<<

或(选择您的选择):

$ gawk -v RS='n<<' '/xxx two/{sub(/^n+/,""); print FILENAME ORS $0 RT}' file
file
XXX >>
 xxx one
 xxx two
 xxx three
<<

,或者如果您在记录之间没有真正的空白行,或者确实没有它们,但不在乎它们是否在输出中复制:

$ gawk -v RS='n<<n' '/xxx two/{printf "%s", FILENAME ORS $0 RT}' file
file
XXX >>
 xxx one
 xxx two
 xxx three
<<

顺便说一句,如果您必须使用非野兽进行此操作,那么您有2个主要选择:

1)将您的真实RS映射到一个字符:

$ awk '{sub(/<</,SUBSEP)}1' file | awk -v f=file 'BEGIN{RS=SUBSEP} /xxx two/{print f ORS $0 "<<"}'
file
XXX >>
 xxx one
 xxx two
 xxx three
<<

2)或通过串联行创建记录的字符串,例如:

$ awk '{rec = rec $0 ORS} /^<</{ if (rec ~ /xxx two/) printf "%s", FILENAME ORS rec; rec=""}' file
file
XXX >>
 xxx one
 xxx two
 xxx three
<<

无论哪种方式,您都不需要建立数组,设置标志,循环等。-始终只需识别/创建记录并在每个记录上进行比较。

我在Endoro提交时正在处理此问题。我认为这在多行上有些可读性。Endoro的解决方案和该解决方案之间的主要区别 - 该解决方案将读取的顺序保持在线条和丢弃的匹配块中,这些块不包含搜索文本:

#!/bin/sh
awk '/>>/ { p=1 }
p     { a[i++]=$0; if(/xxx two/) m=1 }
/<</  {
    if(m) {
        print FILENAME
        for( j=0; j<i; j++ ) { print a[j] }
        m=0
    }
    p=0; i=0; delete a
}' $*

awk块,基本上是:

  • 开始模式
  • 将行存储在"在块中"时,将行存储在"索引"数组中,如果块匹配,请设置标志
  • 在模式的末尾,按顺序打印出数组,然后重置变量并清除数组

这是带有额外; S

的"单行"版本
awk '/>>/ {p=1} p {a[i++]=$0; if(/xxx two/) m=1} /<</{if(m){print FILENAME; for(j=0;j<i;j++) {print a[j]} m=0 } p=0; i=0; delete a}' *.txt

您可以用gawk进行测试:

awk '/xxx one/{f=7};/>>/{delete(s)};{s[++i]=$0};/<</&&f {print FILENAME;for (j in s) print s[j];f=0}' *.txt

要获得有序的输出,请参阅 @Edmorton的评论:

awk '/zzz one/{f=7}/>>/{delete(s);i=0}{s[++i]=$0}/<</&&f {print FILENAME;for (j=1;j<=i;j++) print s[j];f=0}' *.txt

相关内容

  • 没有找到相关文章

最新更新