【问题标题】:Using awk/find to output result and file name使用 awk/find 输出结果和文件名
【发布时间】:2014-02-11 23:25:04
【问题描述】:

三个文件中的示例数据。

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) 和结束分隔符 () 之间的部分。这有效:

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
<<

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

【问题讨论】:

    标签: bash awk find


    【解决方案1】:

    我相信有人会想出一个聪明的解决方案,使用 findexecxargs,但这可以很简单地使用 bashawk 来完成。

    > 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
    <<
    

    或者拆分成看起来更合理的shell脚本

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

    如果您希望它是递归的并且正在使用 bash 4+,您可以将开始的 for 循环替换为

    > shopt -s globstar; for file in /d/Temp/temp/**/*.txt; do
    

    如果您使用的是旧版本的 bash,可以将其替换为 find 循环

    > find /d/Temp/temp/ -type f -name "*.txt" -print0 | while read -r -d '' file; do
    

    【讨论】:

      【解决方案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 一如既往的短线awk(也可以通过使用globstar 执行**/*.txt 来实现递归)。您能否简要解释一下它在您的答案中使用的逻辑。
      • 我已经添加了解释。
      • 我想在脚本中使用它,所以我还需要在 awk 命令部分转义 $ 以便我可以使用位置参数:awk "/${1}/,/&lt;&lt;/{print a[FILENAME]?\$0:FILENAME RS \$0;a[FILENAME]++}" ~/tmp/*.txt
      • 我明白了。感谢更新。
      猜你喜欢
      • 2011-01-08
      • 2016-08-27
      • 2020-06-29
      • 2023-03-31
      • 2017-06-30
      • 1970-01-01
      • 2012-07-01
      • 1970-01-01
      • 2021-07-11
      相关资源
      最近更新 更多