如何将命令输出作为多个参数传递给另一个命令

Posted

技术标签:

【中文标题】如何将命令输出作为多个参数传递给另一个命令【英文标题】: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

【问题讨论】:

使用命令xargs 我猜你的意思是 grep -l... 或者 input 包含一个文件名列表,并且你想要 grep 其中的一个子集。 另见PIping not working with echo command 另见bash pwd and open with pipe not working,里面有非常详细的解释。 【参考方案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

【讨论】:

以上是关于如何将命令输出作为多个参数传递给另一个命令的主要内容,如果未能解决你的问题,请参考以下文章

将 IPython 变量作为参数传递给 bash 命令

如何将数组的值作为第二个参数传递给 awk 的 split 函数?

如何将带有 args 的成员函数作为参数传递给另一个成员函数?

如何将向量作为参数传递给另一个向量?

将命令行参数传递给 AWS Fargate 容器

Perl 如何将数组作为参数传递给另一个 Perl 脚本