为什么find -exec mv {} ./target/ +无法正常工作? (在cygwin上)

我想知道究竟是什么{} \;{} \+| xargs ... | xargs ...做。 请澄清这些解释。

下面的3个命令运行并输出相同的结果,但第一个命令需要一点时间,格式也有点不同。

 find . -type f -exec file {} \; find . -type f -exec file {} \+ find . -type f | xargs file 

这是因为第一个为来自find命令的每个文件运行file命令。 所以,基本上它运行如下:

 file file1.txt file file2.txt 

但后者2find与-exec命令运行文件命令一次像所有文件如下:

 file file1.txt file2.txt 

然后我运行下面的命令,其中第一个运行没有问题,但第二个给出错误信息。

 find . -type f -iname '*.cpp' -exec mv {} ./test/ \; find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ #gives error:find: missing argument to `-exec' 

对于{} \+命令,它给了我错误信息

 find: missing argument to `-exec' 

这是为什么? 任何人都可以请解释我做错了什么?

手册页 (或在线GNU手册 )几乎解释了一切。

find-exec命令{} \;

对于每个结果, command {} 。 所有{}都被replace为文件名。 ; 以斜线作为前缀以防止shell解释它。

find-exec命令{} +

每个结果都附加到command后面执行。 考虑到命令长度限制,我想这个命令可能会执行更多次,手册页支持我:

该命令的总调用次数将远远less于匹配文件的数量。

请注意手册页中的这个引用:

命令行的构build方式与xargs构build其命令行的方式大致相同

这就是为什么在{}+之间不允许有字符,除了空格。 +使查找检测到参数应该像xargs一样附加到命令。

解决scheme

幸运的是, mv的GNU实现可以接受目标目录作为参数,使用-t参数或更长的参数--target 。 它的使用将是:

 mv -t target file1 file2 ... 

你的find命令变成:

 find . -type f -iname '*.cpp' -exec mv -t ./test/ {} \+ 

从手册页:

-exec命令;

执行命令; 如果返回0状态,则返回true。 接下来的所有参数都被认为是命令的参数,直到由“;”组成的参数 遇到。 string“{}”被replace为当前文件名,而不pipe它在命令的参数中出现的位置,而不仅仅是单独存在的参数,就像在某些版本的find中那样。 这两个构造可能需要被转义(用'\')或引号来保护它们免受shell的扩展。 有关使用-exec选项的示例,请参阅EXAMPLES部分。 指定的命令对每个匹配的文件运行一次。 该命令在起始目录中执行。 围绕使用-exec动作存在不可避免的安全问题; 您应该使用-execdir选项。

-exec命令{} +

-exec操作的这种变体在选定的文件上运行指定的命令,但命令行是通过在每个选定的文件名后加上来构build的; 该命令的总调用次数将远远less于匹配文件的数量。 命令行的构build方式与xargs构build其命令行的方式大致相同。 命令中只允许有一个“{}”实例。 该命令在起始目录中执行。

我在Mac OSX上遇到了同样的问题,使用ZSH shell:在这种情况下, mv没有-t选项,所以我必须find另一个解决scheme。 但是,以下命令成功:

 find .* * -maxdepth 0 -not -path '.git' -not -path '.backup' -exec mv '{}' .backup \; 

秘诀是引用大括号exec命令结束时不需要大括号。

我在Ubuntu 14.04下testing(使用BASHZSH shell),它的工作原理是一样的。

但是,使用+符号时,似乎确实必须在exec命令的末尾。

find -iname ... -exec mv -t dest {} +的标准等价物,用于find不支持-iname或不支持-t mv实现的实现,即使用shell来重新排列参数:

 find . -name '*.[cC][pP][pP]' -type f -exec sh -c ' exec mv "$@" /dest/dir/' sh {} + 

通过使用-name '*.[cC][pP][pP]' ,我们也避免依赖当前的语言环境来决定cp的大写forms。

请注意, + ,相反; 在任何shell中都不是特别的,所以不需要引用(尽pipe引用不会造成伤害,除非像rc这样的shell不支持引用操作符)。

尾随/ in /dest/dir/使得mv在发现只有一个cpp文件并且/dest/dir不存在或者不存在的情况下失败,而不是将foo.cpp重命名为/dest/dir ,一个目录(或者符号链接到目录)。

不,和+\;的区别 应该颠倒过来。 +将文件追加到exec命令的末尾,然后运行exec命令和\; 为每个文件运行命令。

问题是find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ find . -type f -iname '*.cpp' -exec mv {} ./test/ \+应该被find . -type f -iname '*.cpp' -exec mv {} ./test/ + find . -type f -iname '*.cpp' -exec mv {} ./test/ +不需要转义或终止+

xargs我已经很久没有用过了,但是我认为它的作用就像+。