为什么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我已经很久没有用过了,但是我认为它的作用就像+。