【问题标题】:Get argument from pipe从管道获取参数
【发布时间】:2013-07-24 16:50:33
【问题描述】:

考虑从管道中获取结果:

find .

现在我想在管道后面的第二个命令中访问实际管道(输入)的内容,然后例如打印两次。

find . | printf $arg$arg\n
#each filename would be printed twice per line

请注意,问题不是要打印两次从管道中获取的任何内容,我知道如何使用 bash for 循环或编写可以完成上述操作的脚本。 如何让 $arg 在内联脚本中快速使用它?

$0 和 $1 不像在脚本文件中那样工作。

【问题讨论】:

    标签: bash pipe xargs


    【解决方案1】:

    简答:您可以使用 sed 将每个文件打印两次:

    find . | sed 's/.*/& &/'
    

    Sed 可以在输入行时对其进行编辑。上面的命令说s(替代).*(整行)& &(本身,两次)。

    更长的答案:当您将一个程序传送到另一个程序时,您将第一个程序的标准输出流连接到第二个程序的标准输入流时间>。第一个程序打印的任何内容都将被视为第二个程序的输入。

    不幸的是,对于您的示例,输入不是逐行块来很好地映射到假设的$args 变量。它来自一个巨大的整体流。如果你想将流的每一行打印两次,你可以使用 sed(它是一个流编辑器),但它只是逐行替换。

    【讨论】:

      【解决方案2】:

      忽略文件名包含换行符的可能性,您可以使用pringley 在他的answer 中建议的sed,或者您可以使用read 命令创建while 循环:

      find . |
      while read -r line
      do
          echo "$line$line"
      done
      

      (-r 用于“原始”输入;它会阻止 shell 扩展输入中的反斜杠转义序列,并且是 shell 中 read 命令的标准 POSIX 功能。)

      由于您提到bash,您可以使用find . -print0 选项以空字节(C 中的'\0')代替换行符来终止每个名称,然后使用:

      find . -print0 |
      while read -r -d '' line
      do
          echo "X${line}${line}X"
      done
      

      -d '' 用字符串参数的第一个字符替换了正常的换行符分隔符,但字符串为空,所以第一个字符是唯一的字符是空字节。

      没有一种简单的方法(据我所知,也没有一种困难的方法)来使用 for 循环,如下所示:

      for line in $(find .)
      do
          echo "X${line}${line}X"
      done
      

      这对于带有空格或换行符的名称可靠地工作。

      通常,您可能想要使用xargs 命令。这会读取标准输入并使用从标准输入中读取的内容作为命令的参数创建命令行。

      find . | xargs wc -l
      

      或者,使用换行符和空格安全(默认情况下,xargs 在空格、制表符和换行符处拆分参数):

      find . -type f -print0 | xargs -0 wc -l
      

      您可以向xargs 申请很多选项——尤其是 GNU 版本。

      但是,您也可以选择find,这在很大程度上使xargs 变得多余:

      find . -type f -exec wc -l {} +
      

      它与find . -print0 | xargs -0 wc -l 命令的工作基本相同。一个区别是,如果find 的输出中没有文件,那么使用-exec 根本不会执行wc,而默认情况下,xargs 将执行一次(没有文件名参数;这是为了符合 POSIX 标准)。使用 GNU xargs,您可以使用 -r 或 --no-run-if-empty 来阻止这种情况的发生。 Mac OS X xargs 似乎无论如何都会这样做。

      【讨论】:

        【解决方案3】:
        find . | xargs -I{} printf "%s%s\n" {} {}
        

        【讨论】:

        • 考虑find . | xargs -I{} printf "%s between %s\n" {}{},试试看,会打印什么?
        • 如果你不在{} 和{} 之间留一个空格,我希望它打印“./file./file between”。如果有是一个空格,我希望“./file between ./file”
        • 我明白了,没错,我不知道大括号是干什么用的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-08-16
        • 2019-06-15
        • 2021-09-16
        • 2016-07-28
        • 1970-01-01
        • 2021-10-16
        • 1970-01-01
        相关资源
        最近更新 更多