【问题标题】:How to grep and execute a command (for every match)如何 grep 和执行命令(对于每个匹配项)
【发布时间】:2012-11-15 16:37:42
【问题描述】:

如何在一个文件中 grep 并为每个匹配执行一个命令?

文件:

foo
bar
42
foo
bar

我想为foo 上的每场比赛执行例如date

以下尝试不起作用:

grep file foo | date %s.%N

怎么做?

【问题讨论】:

    标签: grep


    【解决方案1】:

    在 linux 中有一个有趣的命令:xargs,它允许您使用上一个命令(grep、ls、find 等)的输出作为自定义的输入执行,但有几个选项允许您甚至并行执行自定义命令。下面是一些例子:

    根据您的问题,以下是如何为 file.txt 中的每个“foo”匹配以“%s.%N”格式打印日期:

    grep "foo" file.txt | xargs -I {} date +%s.%N
    

    一个更有趣的用途是为每个匹配项创建一个文件,但在这种情况下,如果匹配项相同,则该文件将被覆盖:

    grep "foo" file.txt | xargs -I {} touch {}
    

    如果您想将自定义日期连接到创建的文件

    grep "foo" file.txt | xargs -I {} touch "{}`date +%s.%N`"
    

    想象匹配是文件名,而您想要对它们进行备份:

    grep "foo" file.txt | xargs -I {} cp {} "{}.backup"
    

    最后对于 xargs 使用备份名称中的自定义日期

    grep "foo" file.txt | xargs -I {} cp {} "{}`date +%s.%N`"
    

    有关 xargs 并行执行等选项的更多信息,请访问:https://en.wikipedia.org/wiki/Xargs 和日期格式:https://www.thegeekstuff.com/2013/05/date-command-examples/

    我还发现一个普通的 for 命令在这种情况下也很有用它更简单但通用性较差,下面是上述示例的等价物:

    for i in `grep "foo" test.txt`; do date +%s.%N; done
    for i in `grep "foo" test.txt`; do touch ${i}; done
    for i in `grep "foo" test.txt`; do touch "${i}`date +%s.%N`"; done
    for i in `grep "foo" test.txt`; do cp ${i} "${i}.backup2"; done
    for i in `grep "foo" test.txt`; do cp ${i} "${i}.backup2`date +%s.%N`"; done
    

    玩得开心!!!

    【讨论】:

      【解决方案2】:

      您真正需要的是 xargs 命令。 http://en.wikipedia.org/wiki/Xargs

      grep file foo | xargs date %s.%N
      

      在 Cygwin 环境中匹配某些文件并将匹配转换为完整 windows 路径的示例

      $ find $(pwd) -type f -exec ls -1 {} \; | grep '\(_en\|_es\|_zh\)\.\(path\)$' | xargs cygpath -w
      

      【讨论】:

        【解决方案3】:
        grep file foo | while read line ; do echo "$line" | date %s.%N ; done
        

        在脚本中更具可读性:

        grep file foo | while read line
        do
            echo "$line" | date %s.%N
        done
        

        对于每一行输入,read 会将值放入变量$linewhile 语句将执行dodone 之间的循环体。由于该值现在位于变量中而不是标准输入中,因此我使用echo 将其推回标准输入,但您可以只使用date %s.%N "$line",假设日期是这样工作的。

        避免使用类似的for line in `grep file foo`,因为for 总是在空格处中断,这成为读取文件列表的噩梦:

         find . -iname "*blah*.dat" | while read filename; do ....
        

        会因for 而失败。

        【讨论】:

        • 没问题。大多数批量任务都有 unix 工具,包括 grep 从文件中读取多个模式 (-f) 的能力,或 xargs 从标准输入构造命令的能力。
        • 这不应该是:grep foo file ------- NAME grep, egrep, fgrep, rgrep - 打印与模式匹配的行 SYNOPSIS grep [OPTIONS] PATTERN [FILE...]
        • 如何执行脚本:grep file foo | while read line do echo "$line" | date %s.%N done 我需要放入文件吗?
        • @EsNoguera 如果你愿意,你可以。您可以在命令行上运行它,方法是将; 放在行之间,例如grep file foo | while read line; do echo "$line" | date %s.%N; done。要从文件运行任何命令(包括该命令),只需将 #!/bin/bash 放在文件顶部(我会运行 which bash 以找出您的 bash 所在的位置),粘贴命令,保存并将其标记为可执行:chmod +x <scriptfile>.
        • 要立即执行匹配,请执行类似./test.sh | tee /dev/tty | stdbuf -o0 egrep '(foo|bar)' |while read line; do echo "FOUND $line"; done
        【解决方案4】:
        grep command_string file | sh - 
        

        【讨论】:

          【解决方案5】:

          grep 可能需要--line-buffered 选项来在匹配时发出每个匹配行,否则它会在打印匹配行之前缓冲多达 4K 字节,这会破坏这里的目标,例如

          tail -f source | grep --line-buffered "expression | xargs ...
          

          【讨论】:

            【解决方案6】:
                grep search_string files_to_search | sh
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-06-21
              • 1970-01-01
              • 1970-01-01
              • 2020-03-03
              • 1970-01-01
              • 2015-12-22
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多