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

时间:2015-10-30 08:45:43

标签: linux shell unix

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

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

5 个答案:

答案 0 :(得分:17)

您可以使用xargs

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

答案 1 :(得分:5)

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

答案 2 :(得分:4)

除了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

答案 3 :(得分:1)

为了完整起见,我还会提到命令替换,并解释为什么不推荐:

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选项允许您将目标目录放在第一个在命令行中,您可以在命令末尾添加任意数量的文件:)

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

将扩展为

cp -t destdir file1 file2 file3 file4 ...

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

换句话说,如果您使用命令替换语法并且grep生成真正的长匹配列表,您可能会遇到ARG_MAX和"参数列表太长"错误;但是xargs会明确地避免这种情况,而是只复制尽可能多的参数,因为它一次可以安全地传递给cp,并在必要时多次运行cp

答案 4 :(得分:0)

#!/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