使用awk / find输出结果和文件名

时间:2014-01-22 03:56:19

标签: bash awk find

三个文件中的示例数据。

fileOne.txt

YYY >>
 yyy one
 yyy two
 yyy three
<<

ZZZ >>
 zzz one
 zzz two
 zzz three
<<

fileTwo.txt

XXX >>
 xxx one
 xxx two
 xxx three
<<

fileThree.txt

XXX >>
 xxx one
 xxx two
 xxx three
<<

ZZZ >>
 zzz one
 zzz two
 zzz three
<<

我使用awk在起始分隔符( XXX )和结束分隔符(&lt;&lt; )之间输出文件的部分内容。这有效:

awk '/XXX/,/<</' /d/Temp/temp/*.txt

结果

XXX >>
 xxx one
 xxx two
 xxx three
<<
XXX >>
 xxx one
 xxx two
 xxx three
<<

但我也要输出文件名。找到一些作品,但最终打印所有文件名。

find /d/Temp/temp/ -type f -name "*.txt" -print -exec awk '/XXX/,/<</' {} \;

结果

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

如何修改此命令以仅输出匹配的文件名?

2 个答案:

答案 0 :(得分:2)

使用awk

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

说明:

/XXX/,/<</                      # output portions of the file between start delimiter (XXX) and end delimiter (<<). 
a[FILENAME]?                    # assign filename as key to array `a`, determine whether it is the true (>0) or fails (0 or null)
a[FILENAME]?$0:FILENAME RS $0   # if true, print the line only, if fail, print filename and the current line
a[FILENAME]++                   # increase the value of array a[FILENAME]

答案 1 :(得分:1)

我确信有人会使用findexecxargs提出一个聪明的解决方案,但只需使用bash和{ {1}}。

awk

或拆分成更合理的shell脚本

> for file in /d/Temp/temp/*.txt; do res=$(awk '/XXX/,/<</' "$file"); [[ $res != "" ]] && echo "$file" && echo "$res"; done
/d/Temp/temp/fileThree.txt
XXX >>
 xxx one
 xxx two
 xxx three
<<
/d/Temp/temp/fileTwo.txt
XXX >>
 xxx one
 xxx two
 xxx three
<<

如果你想要它是递归的并且正在使用bash 4+,你可以用

替换起始for循环
#!/bin/bash
for file in "/d/Temp/temp/"*.txt; do 
  res=$(awk '/XXX/,/<</' "$file")
  [[ $res != "" ]] && echo "$file" && echo "$res" 
done

如果您使用的是旧版本的bash,则可以将其替换为> shopt -s globstar; for file in /d/Temp/temp/**/*.txt; do 循环

find