为了完整起见,我还将提及命令替换并解释为什么不推荐这样做:
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 选项允许您将目标目录 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。