【问题标题】:How to process each output line in a loop?如何处理循环中的每个输出行?
【发布时间】:2013-04-25 10:33:29
【问题描述】:

在运行grep 命令后,我从一个文件中检索了许多行,如下所示:

var=`grep xyz abc.txt`

假设我得到了 10 行,结果由 xyz 组成。

现在我需要处理由于 grep 命令而得到的每一行。我该怎么做?

【问题讨论】:

  • 这里的答案都没有提到grep -o 对这类事情的影响。 -o 标志将返回 only 匹配的文本,每行输出一个匹配项。 (它并不详尽,所以echo aaa |grep 'a*' 只给你“aaa”并省略了三个部分匹配“”、“a”和“aa”)

标签: bash shell grep


【解决方案1】:

对于那些寻找单线的人:

grep xyz abc.txt | while read -r line; do echo "Processing $line"; done

【讨论】:

  • 非常需要这个,非常感谢
【解决方案2】:

使用 while/read 循环遍历 grep 结果。 喜欢:

grep pattern filename.txt | while read -r line ; do
    echo "Matched Line:  $line"
    # your code goes here
done

【讨论】:

    【解决方案3】:

    无需使用 --line-buffered grep 选项进行任何迭代:

    your_command | grep --line-buffered "your search"
    

    带有 Symfony PHP Framework 路由器调试命令输出的真实示例,用于 grep 所有“api”相关路由:

    php bin/console d:r | grep --line-buffered "api"
    

    【讨论】:

    • 如果 your_command 长时间运行(例如 tail -f some.log,在我的情况下),唯一可行的解​​决方案...
    【解决方案4】:

    通常处理的顺序并不重要。 GNU Parallel 就是为这种情况而设计的:

    grep xyz abc.txt | parallel echo do stuff to {}
    

    如果你的处理更像:

    grep xyz abc.txt | myprogram_reading_from_stdin
    

    myprogram 很慢那么你可以运行:

    grep xyz abc.txt | parallel --pipe myprogram_reading_from_stdin
    

    【讨论】:

      【解决方案5】:

      一种简单的方法是不要将输出存储在变量中,而是直接使用 while/read 循环对其进行迭代。

      类似:

      grep xyz abc.txt | while read -r line ; do
          echo "Processing $line"
          # your code goes here
      done
      

      根据您所追求的具体内容,此方案会有所不同。

      如果您需要更改循环内的变量(并使该更改在循环外可见),您可以使用fedorqui's answer 中所述的进程替换:

      while read -r line ; do
          echo "Processing $line"
          # your code goes here
      done < <(grep xyz abc.txt)
      

      【讨论】:

      • 如果没有 xyz 行?
      • 然后什么都没有发生,循环没有运行。
      • 这种方法的问题是(因为管道)循环内的所有东西都在一个子shell中,所以在循环期间设置循环外定义的变量不会使它们的值在循环后可用!
      • @David:提供了一个替代方案来解决您的问题。 (fedorqui 也已经解决了这个问题。)
      • 对于最后一行输出没有以换行符终止的命令,您需要:while read p || [[ -n $p ]]; do ...(借用自stackoverflow.com/questions/1521462/…
      【解决方案6】:

      您可以执行以下while read 循环,该循环将使用所谓的进程替换由grep 命令的结果提供:

      while IFS= read -r result
      do
          #whatever with value $result
      done < <(grep "xyz" abc.txt)
      

      这样,您不必将结果存储在变量中,而是直接将其输出“注入”到循环中。


      根据 BashFAQ/001 中的建议注意 IFS=read -r 的用法:How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?

      读取的 -r 选项可防止反斜杠解释(通常使用 作为反斜杠换行符对,继续多行或 转义分隔符)。如果没有这个选项,任何未转义的反斜杠 在输入中将被丢弃。你应该几乎总是使用 -r 带有读取的选项。

      在上面的场景中 IFS= 防止修剪前导和尾随 空白。如果您想要这种效果,请将其删除。

      关于进程替换,在bash hackers page中有说明:

      进程替换是一种重定向形式,其中输入或 进程的输出(某些命令序列)显示为临时的 文件。

      【讨论】:

      • 好的,我打了for 版本。尝试像在stackoverflow.com/a/14588210/1983854 中一样在"${$(grep xyz abc.txt)[@]}" 上循环,但不能。所以我只留下第一个版本。
      • 您不能将参数扩展应用于命令替换(除非您使用 zsh,这种嵌套可能会起作用)。
      • 这个习惯用法的一个可能问题是,如果循环内的任何内容试图从标准输入中读取,它将获得文件的一部分。为了避免这种可能性,我喜欢通过文件描述符 3 而不是标准输入来发送文件。只需使用while IFS= read -r result &lt;&amp;3done 3&lt; &lt;(grep ...
      • 我知道最初的问题是针对 bash 提出的,但对于未来的读者:这不符合 POSIX 标准。 shellcheck(SC2039):在 POSIX sh 中,进程替换是未定义的。
      【解决方案7】:

      我建议在这里使用 awk 而不是 grep + 其他东西。

      awk '$0~/xyz/{ //your code goes here}' abc.txt

      【讨论】:

      • 如何引用//your code goes here 中找到的完整行?
      • @user857990 整行在 AWK 中表示为 $0。
      猜你喜欢
      • 2014-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-30
      • 2018-07-02
      相关资源
      最近更新 更多