我想将命令的每个输出作为多个参数传递给第二个命令,例如:
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
答案 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的情况,您需要单独引用每个匹配并为其添加扩展名,xargs
或while 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