【问题标题】:How to pass command output as multiple arguments to another command如何将命令输出作为多个参数传递给另一个命令
【发布时间】:2016-01-30 15:13:22
【问题描述】:

我想将命令的每个输出作为多个参数传递给第二个命令,例如:

grep "pattern" input

返回:

file1
file2
file3

我想复制这些输出,例如:

cp file1  file1.bac
cp file2  file2.bac
cp file3  file3.bac

我怎样才能一口气做到这一点?比如:

grep "pattern" input | cp $1  $1.bac

【问题讨论】:

标签: linux shell unix


【解决方案1】:

你可以使用xargs:

grep 'pattern' input | xargs -I% cp "%" "%.bac"

【讨论】:

    【解决方案2】:

    您可以使用$() 插入命令的输出。所以,如果你愿意,你可以使用kill -9 $(grep -hP '^\d+$' $(ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'))

    【讨论】:

      【解决方案3】:

      除了Chris Jester-Young good answer,我想说xargs对于这些情况也是一个很好的解决方案:

      grep ... `ls -lad ... | awk '{ print $9 }'` | xargs kill -9
      

      会成功的。一起来:

      grep -hP '^\d+$' `ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'` | xargs kill -9
      

      【讨论】:

        【解决方案4】:

        为了完整起见,我还将提及命令替换并解释为什么不推荐这样做:

        cp $(grep -l "pattern" input) directory/
        

        (反引号语法cp `grep -l "pattern" input` directory/ 大致相同,但它已过时且笨拙;不要使用它。)

        如果 grep 的输出生成的文件名包含空格或 shell 元字符,这将失败。

        当然,如果您确切地知道grep 可以生成哪些文件名,并且已验证它们都没有问题,则可以使用它。但对于生产脚本,不要使用它。

        无论如何,对于 OP 的场景,您需要单独引用每个匹配项并为其添加扩展名,xargswhile read 替代方案无论如何都是优越的。

        在最坏的情况下(意味着有问题或未指定的文件名),通过xargs 将匹配项传递给子shell:

        grep -l "pattern" input |
        xargs -r sh -c 'for f; do cp "$f" "$f.bac"; done' _
        

        ...for 循环内的脚本显然可以任意复杂。

        在理想情况下,您要运行的命令足够简单(或通用),您可以简单地向它传递任意长的文件名列表。例如,GNU cp 有一个 -t 选项来促进 xargs 的这种使用(-t 选项允许您将目标目录 first 放在命令行上,这样您就可以在命令末尾添加任意数量的文件):

        grep -l "pattern" input | xargs cp -t destdir
        

        这将扩展为

        cp -t destdir file1 file2 file3 file4 ...
        

        xargs 可以匹配到cp 的命令行,重复多次以将所有文件传递给cp。 (不幸的是,这与 OP 的场景不匹配;如果您需要在复制时重命名每个文件,则每次 cp 调用只需传入两个参数:源文件名和将其复制到的目标文件名。 )

        换句话说,如果您使用命令替换语法并且grep 生成了一个非常 长的匹配列表,您可能会遇到ARG_MAX 和“Argument list too long”错误;但是xargs 会特别避免这种情况,而是一次只复制可以安全传递给cp 的尽可能多的参数,并在必要时多次运行cp

        【讨论】:

          【解决方案5】:
          #!/bin/bash
          
          for f in files; do
            if grep -q PATTERN "$f"; then
              echo cp -v "$f" "${f}.bac"
            fi
          done
          

          文件可以是 *.txt 或 *.text ,这基本上意味着文件以 *.txt 或 *text 结尾或替换为您想要/需要的东西,当然用您的替换 PATTERN。如果您对输出感到满意,请删除 echo。对于递归解决方案,请查看 bash shell 选项 globstar

          【讨论】:

            猜你喜欢
            • 2014-12-03
            • 2017-08-30
            • 2012-07-08
            • 1970-01-01
            • 2021-04-19
            • 2012-10-25
            • 1970-01-01
            相关资源
            最近更新 更多