Answers:
最好用一个例子来说明。假设find
打开了这些文件:
file1
file2
file3
使用-exec
用分号(find . -exec ls '{}' \;
),将执行
ls file1
ls file2
ls file3
但是,如果您使用加号代替(find . -exec ls '{}' \+
),则将尽可能多的文件名作为参数传递给单个命令:
ls file1 file2 file3
文件名的数量仅受系统最大命令行长度的限制。如果命令超过此长度,则该命令将被多次调用。
+
关联-exec
总是被转义,但是+
与关联-mtime
却不是。你知道原因吗?我猜这是逃避;
与关联的习惯-exec
。
;
。无法想象有必要逃脱+
到目前为止,所有答案都是正确的。我提供此信息是(对我来说)使用echo
而不是来更清楚地说明所描述的行为ls
:
对于分号,echo
每个找到的文件(或其他文件系统对象)将调用一次命令:
$ find . -name 'test*' -exec echo {} \;
./test.c
./test.cpp
./test.new
./test.php
./test.py
./test.sh
带加号的命令echo
仅被调用一次。找到的每个文件都作为参数传递。
$ find . -name 'test*' -exec echo {} \+
./test.c ./test.cpp ./test.new ./test.php ./test.py ./test.sh
如果find
出现大量结果,您可能会发现该命令在参数数量上被阻塞。
xargs
做的...从原则上讲,它永远不会阻塞太多的争论。
find
都将尝试避免达到参数数量的限制。包括Solaris'(至少10个)。如果您做类似find ... -exec ksh -c 'cmd "$@" "$@"' sh {} +
或的事情find ... -exec ksh -c 'files="$*" cmd "$@"' sh {} +
,它可能会失败,但find
不能为此而怪罪。请注意,GNU find
是最后find
要支持的实现之一+
(曾经是将脚本移植到GNU系统的一种痛苦)。
来自man find
:
-exec命令;
执行命令;如果返回0状态,则为true。后面的所有要查找的参数都将被视为命令的参数,直到由';'组成的参数为止 遇到。字符串'{}'被当前文件名替换,该文件名在命令的参数中出现的所有位置(而不仅仅是在单独的参数中,如在find的某些版本中)都在处理。这两种构造都可能需要转义(带有'\')或加引号,以防止它们被外壳扩展。有关使用'-exec'选项的示例,请参见示例秒部分。对于每个匹配的文件,指定的命令运行一次。 该命令在起始目录中执行。围绕-exec选项的使用存在不可避免的安全性问题。
-exec命令{} +
-exec选项的此变体在选定的文件上运行指定的命令,但是通过在末尾附加每个选定的文件名来构建命令行;该命令的调用总数将远远少于匹配文件的数目。命令行的构建与xargs构建命令行的方式几乎相同。命令中仅允许使用一个'{}'实例。该命令在起始目录中执行。
因此,据我了解,它对所\;
找到的每个文件执行单独的命令find
,而\+
追加文件并在所有文件上执行单个命令。该\
是一个转义字符,所以它是:
ls testdir1; ls testdir2
与
ls testdir1 testdir2
在我的shell中执行上述操作即可反映您问题中的输出。
\+
假设有两个文件,1.tmp
和2.tmp
:
1.tmp:
1
2
3
2.tmp:
0
2
3
与\;
:
find *.tmp -exec diff {} \;
> diff: missing operand after `1.tmp'
> diff: Try `diff --help' for more information.
> diff: missing operand after `2.tmp'
> diff: Try `diff --help' for more information.
而如果您使用\+
(连接的结果find
):
find *.tmp -exec diff {} \+
1c1,3
< 1
---
> 0
> 2
> 30
因此,在这种情况下diff 1.tmp; diff 2.tmp
,diff 1.tmp 2.tmp
在某些情况下\;
适当且\+
必要。使用\+
with rm
是这样的一种情况,如果要删除大量文件,性能(速度)将优于\;
。
find
具有特殊的语法。您按{}
原样使用,因为它们的含义是找到所找到文件的路径名,并且(大多数)shell不会以其他方式解释它们。您需要反斜杠,\;
因为分号对shell有意义,它在find
获得外壳之前先将其吃光了。因此find
,在传递给C程序的参数列表中,要看完外壳之后要看的是:
“ -exec”,“ rm”,“ {}”,“;”
但是您需要\;
在命令行上通过外壳将分号传递给参数。
您可以避免,\{\}
因为shell引用的解释\{\}
是just {}
。同样,您可以使用'{}'。
你不能做的就是使用
-exec 'rm {} ;'
因为外壳程序将其解释为一个参数,
“ -exec”,“ rm {};”
而rm {} ;
不是命令的名称。(至少除非有人真的搞砸了。)
更新资料
区别在于
$ ls file1
$ ls file2
和
$ ls file1 file2
该+
被catenating名称到一个命令行。
;
(分号)或+
(加号)之间的区别在于参数如何传递到find的-exec
/ -execdir
参数中。例如:
using ;
将执行多个命令(每个参数分别执行),
例:
$ find /etc/rc* -exec echo Arg: {} ';'
Arg: /etc/rc.common
Arg: /etc/rc.common~previous
Arg: /etc/rc.local
Arg: /etc/rc.netboot
后面的所有自变量
find
均作为命令的自变量。该字符串
{}
将替换为当前正在处理的文件名。
using +
将执行最少的命令(因为参数组合在一起)。这与xargs
命令的工作原理非常相似,因此它将在每个命令中使用尽可能多的参数,以避免超出每行参数的最大限制。
例:
$ find /etc/rc* -exec echo Arg: {} '+'
Arg: /etc/rc.common /etc/rc.common~previous /etc/rc.local /etc/rc.netboot
通过在每个末尾附加每个选定的文件名来构建命令行。
命令中仅
{}
允许的一个实例。
也可以看看: