为了完整起见,我还会提到命令替换,并解释为什么不建议使用:
cp $(grep -l "pattern" input) directory/
(反引号语法 cp `grep -l "pattern" input` directory/
大致相当,但已经过时且笨重; 不要使用它。)
如果grep
的输出产生包含空格或shell元字符的文件名,则此方法将失败。
当然,如果您确切知道grep
可以产生哪些文件名,并验证了它们中没有问题文件名,那么使用此方法是可以的。但对于生产脚本,请不要使用此方法。
无论如何,在需要单独引用每个匹配项并为其添加扩展名的情况下,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
和"Argument list too long"错误;但是
xargs
将通过仅复制它可以安全传递给
cp
的参数数量来避免此问题,并在必要时运行多次
cp
。
上述内容仍然无法正确处理包含换行符的文件名。也许还可以参考
https://mywiki.wooledge.org/BashFAQ/020。
xargs
。 - el.pescado - нет войнеgrep -l
... 或者input
包含文件名列表,你想要在其中的一个子集中进行 grep。 - tripleee