【问题标题】:Use pipe of commands as argument for diff使用命令管道作为 diff 的参数
【发布时间】:2012-04-08 12:02:31
【问题描述】:

这个简单的任务我遇到了麻烦:

cat file | grep -E ^[0-9]+$ > file_grep
diff file file_grep

问题是,我想在没有file_grep 的情况下执行此操作

我试过了:

diff file `cat file | grep -E ^[0-9]+$`

diff file "`cat file | grep -E ^[0-9]+$`"

和其他一些组合:-) 但我无法让它工作。 当diff 获得额外参数时,我总是会收到错误消息,该参数是由grep 过滤的文件内容。

当我想在这样的脚本中 echo 命令输出时,类似的东西总是对我有用(使用反引号转义):

echo `ls`

谢谢

【问题讨论】:

    标签: bash grep diff


    【解决方案1】:

    最简单的方法是:

    grep -E '^[0-9]+$' file | diff file -
    

    作为文件名的连字符- 是一个特定的符号,它告诉diff“使用标准输入”;它记录在diff 手册页中。 (大多数常用实用程序都支持相同的符号。)

    反引号不起作用的原因是它们捕获命令的输出并将其作为参数传递。例如,这个:

    cat `echo file`
    

    等价于:

    cat file
    

    还有这个:

    diff file "`cat file | grep -E ^[0-9]+$`"
    

    相当于这样的:

    diff file "123
    234
    456"
    

    也就是说,它实际上尝试将123234345(加上换行符)作为文件名,而不是作为文件的内容。从技术上讲,您可以通过使用 Bash 的“进程替换”功能来实现后者,该功能实际上会创建一种临时文件:

    diff file <(cat file | grep -E '^[0-9]+$')
    

    但在您的情况下不需要,因为diff 支持-

    【讨论】:

    • 我可以像这样将整个命令放在测试中吗? if [ -z grep -E '^[0-9]+$' file | diff file - ]; then echo "matches" fi
    • @Pan.student:你实际上不需要使用[ -z ... ],因为如果文件之间没有差异,diff 返回0 ("success/true"),并且1 ("failure/false") 如果有的话,你可以写 if grep -E '^[0-9]+$' file | diff file - &gt;/dev/null ; then echo matches ; fi 。 . .就此而言,您实际上也不需要使用diff,因为如果找到行,grep 返回0,否则返回1,因此您可以只写if ! grep '[^0-9]' file &gt;/dev/null ; then echo matches ; fi 来确认有没有包含0-9以外字符的行。
    【解决方案2】:

    如果您使用的是 bash:

    diff file <(grep -E '^[0-9]+$' file)
    

    &lt;(COMMAND) 序列扩展为伪文件的名称(例如/dev/fd/63),您可以从中读取命令的输出。

    但对于这种特殊情况,ruakh 的解决方案更简单。它利用- 作为diff 的参数这一事实使其读取其标准输入。当diff 的两个参数都是命令输出时,&lt;(COMMAND) 语法变得更加有用,例如:

    diff <(this_command) <(that_command)
    

    【讨论】:

    • 本帖中的第一个命令不正确,将不起作用。 file 的第二个实例必须在 ( ) 内。按原样编写,grep 命令不会在file 上运行。正确版本:diff file &lt;(grep -E '^[0-9]+$' file)
    【解决方案3】:

    在 bash 中,语法是

    diff file <(cat file | grep -E ^[0-9]+$)
    

    【讨论】:

      【解决方案4】:

      尝试进程替换:

      $ diff file <(grep -E "^[0-9]+$" file)
      

      来自 bash 手册页:

      流程替换

      在支持命名管道 (FIFO) 或 /dev/fd 方法的系统上支持进程替换 命名打开的文件。它采用 (list) 的形式。进程列表使用其输入运行或 输出连接到 FIFO 或 /dev/fd 中的某个文件。此文件的名称作为参数传递给 当前命令作为扩展的结果。如果使用 >(list) 形式,则写入文件 将为列表提供输入。如果使用

      【讨论】:

        【解决方案5】:
        grep -E '^[0-9]+$' file | diff - file
        

        其中- 表示“从标准输入读取”。

        【讨论】:

          猜你喜欢
          • 2016-09-21
          • 2012-03-27
          • 1970-01-01
          • 2019-02-16
          • 2020-04-12
          • 1970-01-01
          • 2019-03-26
          • 2012-04-16
          相关资源
          最近更新 更多