为什么我不能将查找结果通过管道传输到 cp,但它可以使用 exec?

Why can't I pipe find results into cp, but it works using exec?

我正在使用 find 列出多个目录中具有特定扩展名的文件。我试过了

find /path/to/encompassing/directory/ -d -name "*modified.tif" | xargs  cp Destination_Directory/ 

但是没用。使用

find /path/ -d -name "*modified.tif" -type f -exec cp {} Destination_Directory \;

有效,但我不明白为什么 xargs 不起作用。

我不使用 xargs,但我认为它应该像这样工作:

cp `find  /path/to/encompassing/directory/ -d  -name "*modified.tif"` Destination_Directory/

那就不用管了。

如果你写

find -name '*modified.tif' | xargs cp directory

那就和写一样了

cp directory file1modified.tif file2modified.tif

(或任何匹配的文件名),这是错误的方法,因为 xargs 默认附加参数。

find -name '*modified.tif' -exec cp {} directory \;

相同
cp file1modified.tif directory
cp file2modified.tif directory

这就是你想要的。

您可以使用

实现与 xargs 相同的效果
xargs -I{} cp {} directory

指定要在命令中使用参数的位置,但这意味着一次只会复制一个文件(因为 -I 意味着 -L1)。

为避免每个文件调用一次 cp,您可以对 cp 使用 -t 选项,以便可以将要复制的文件附加到命令的末尾(需要GNU cp):

find -name '*modified.tif' | xargs cp -t directory

相当于

cp -t directory file1modified.tif file2modified.tif

或更好,处理文件名中的空白,

find -name '*modified.tif' -print0 | xargs -0 cp -t directory

或者,没有 xargs

find -name '*modified.tif' -exec cp -t directory {} +

其中 -exec {} + 确保尽可能少地调用 cp

xargs 将其标准输入中的每个单词作为 last 参数传递给 cp,而不是第一个。因此,您正在尝试 运行 一系列命令

cp Destination_Directory/ foo
cp Destination_Directory/ bar
# etc

如果您使用的是 GNU cp,您可以简单地通过使用 -t 选项来指定 Destination_Directory 目标 来解决这个问题],而不是来源。

... | xargs cp -t Destination_Directory
# cp -t Destination_Directory foo
# cp -t Destination_Directory bar
# etc

可能能够使用xargs中的-I选项使其使用传入的文件名作为第一个参数:

... | xargs -I '{}' cp '{}' Destination_Directory

然而,这对 find 将产生的名称做了很多假设。 (没有前导或尾随空格,文件名中也没有换行符。)(就此而言,xargs without -I 正在处理每个以空格分隔的 word 作为调用 cp 的单独参数。)通常,您不应尝试以编程方式使用 find 的输出。坚持使用它的 -exec 主节点。

您的代码

find /path/ -d -name "*modified.tif" -type f -exec cp {} Destination_Directory \;

是正确的方法。不涉及 shell,因此每个文件名都按原样 作为 作为第一个参数传递给 cp.