这是使用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