为什么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(使用BASH和ZSH 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]' ,我们也避免依赖当前的语言环境来决定c或p的大写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我已经很久没有用过了,但是我认为它的作用就像+。