在find中使用分号(;)vs plus(+)和exec

Ank*_*wal 140 find

为什么使用之间的输出存在差异

find . -exec ls '{}' \+
Run Code Online (Sandbox Code Playgroud)

find . -exec ls '{}' \;
Run Code Online (Sandbox Code Playgroud)

我有:

$ find . -exec ls  \{\} \+
./file1  ./file2

.:
file1  file2  testdir1

./testdir1:
testdir2

./testdir1/testdir2:


$ find . -exec ls  \{\} \;
file1  file2  testdir1
testdir2
./file2
./file1
Run Code Online (Sandbox Code Playgroud)

Mar*_*tin 222

用一个例子可能最好地说明了这一点.让我们说find这些文件:

file1
file2
file3
Run Code Online (Sandbox Code Playgroud)

使用-exec分号(find . -exec ls '{}' \;),将执行

ls file1
ls file2
ls file3
Run Code Online (Sandbox Code Playgroud)

但是如果你使用加号代替(find . -exec ls '{}' \+),尽可能多的文件名作为参数传递给单个命令:

ls file1 file2 file3
Run Code Online (Sandbox Code Playgroud)

文件名的数量仅受系统的最大命令行长度限制.如果命令超过此长度,则将多次调用该命令.

  • Dumb q:我注意到与 `-exec` 相关的 `+` 总是被转义,但与 `-mtime` 相关的 `+` 不是。你知道原因吗?我想这是逃避与`-exec`相关的`;`的习惯。 (3认同)
  • 确实,@ kevinarpe,我会把它归类为`;`的习惯。无法想象有必要逃避`+` (3认同)
  • 谢谢。这对于想要对结果文件进行排序非常有用: find -maxdepth 1 -type f -mtime -1 -exec ls -ltr {} \+ (2认同)

Joh*_*web 35

到目前为止,所有答案都是正确的.我提供这个更清楚(对我来说)使用echo而不是ls:

使用分号,echo每个文件(或其他文件系统对象)找到一次命令:

$ find . -name 'test*' -exec echo {} \;
./test.c
./test.cpp
./test.new
./test.php
./test.py
./test.sh
Run Code Online (Sandbox Code Playgroud)

使用加号,该命令echo仅被调用一次.找到的每个文件都作为参数传入.

$ find . -name 'test*' -exec echo {} \+
./test.c ./test.cpp ./test.new ./test.php ./test.py ./test.sh
Run Code Online (Sandbox Code Playgroud)

如果find出现大量结果,您可能会发现被调用的命令会对参数的数量产生阻塞.

  • 好插图! (3认同)
  • @Rmano:我已经看到 Solaris 上的 `find`(和 `xargs`)发出的参数比消耗的多。[GNU 的 findutils`](http://savannah.gnu.org/git/?group=findutils) 中的 `xargs`(和 `find`)似乎表现得更明智,但并不是每个人都使用 GNU。 (3认同)
  • find 不应该只将结果添加到一个可以安全地将其传递给 shell 的数字吗?至少是 `xargs` 所做的......原则上它永远不会因为太多的争论而窒息。 (2认同)
  • @Johnsyweb,所有POSIX`find`都会尽量避免达到参数数量的限制.这包括Solaris'(至少10个).它可能失败的地方是你做的事情就像`find ... -exec ksh -c'cmd"$ @""$ @"'sh {} +`或`find ... -exec ksh -c'ciles = "$*"cmd"$ @"'sh {} +`,但`find`真的不能归咎于此.请注意,GNU`find`是最后一个支持`+`的`find`实现之一(曾经很难将脚本移植到GNU系统). (2认同)

mat*_*hew 16

来自那个男人

-exec命令;

执行命令; 如果返回0状态,则返回true.查找的所有后续参数都被视为命令的参数,直到由';'组成的参数为止 遇到了.字符串"{}"将被当前文件名替换,该文件名将在命令的参数中出现,而不仅仅是在单独的参数中,就像在某些版本的find中一样.这两种结构都可能需要进行转义(使用'\')或引用以保护它们不被shell扩展.有关使用'-exec'选项的示例,请参见示例部分.为每个匹配的文件运行一次指定的命令.该命令在起始目录中执行.使用-exec选项时存在不可避免的安全问题; 你应该使用-execdir选项.

-exec命令{} +

-exec选项的此变体在所选文件上运行指定的命令,但命令行是通过在末尾附加每个选定的文件名来构建的; 命令的调用总数将远远少于匹配文件的数量.命令行的构建方式与xargs构建命令行的方式大致相同.命令中只允许一个"{}"实例.该命令在起始目录中执行.

所以我理解它的方式,\; 执行单独的命令,+附加每个名称.它基本上就是它的执行方式,因为它是一个逃避所以它

ls testdir1; ls testdir2 
Run Code Online (Sandbox Code Playgroud)

VS

ls testdir1 testdir2
Run Code Online (Sandbox Code Playgroud)

在我的shell中执行上述操作镜像输出您的问题.

更新2

那么,你为什么要用+

说我有两个文件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.
Run Code Online (Sandbox Code Playgroud)

如果您使用+并连接查找结果,如下所示:

find *.tmp -exec diff {} \+
1c1,3
< 1
---
> 0
> 2
> 30
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下它的区别是差异1.tmp; diff 2.tmp和diff 1.tmp 2.tmp

有些情况下\; 是合适的+将是必要的.使用+ with rm就是这样一个实例,如果要删除大量文件,速度会大大提高; 我总是喜欢学习更多关于find的知识,它是如此强大且方便的工具我希望这足以解释差异.

  • 我认为 -1 不公平,我解释了我对这个人的理解。我并没有效仿那个人然后离开。但我编辑了我的回复以包含更好的示例。 (3认同)

Cha*_*tin 9

这是交易:find有特殊的语法.您可以使用{}原样,因为它们具有找到找到的文件的路径名的意义,并且(大多数)shell不会解释它们.你需要反斜杠,\;因为分号对shell有意义,它会在找到之前把它吃掉.因此,在传递给C程序的参数列表中,找到想要在shell完成之后看到的是

"-exec","rm","{}",";"

但是你需要\;在命令行上通过shell获得一个分号到参数.

你可以逃脱,\{\}因为shell引用的解释\{\}只是{}.同样,您可以使用"{}".

不能做的是使用

 -exec 'rm {} ;'
Run Code Online (Sandbox Code Playgroud)

因为shell将其解释为一个参数,

"-exec","rm {};"

和"rm {};" 不是命令的名称.(至少除非有人真的搞砸了.)

更新

区别在于

$ ls file1
$ ls file2
Run Code Online (Sandbox Code Playgroud)

$ ls file1 file2
Run Code Online (Sandbox Code Playgroud)

+正在命令行上连接名称.

  • 这是一个很好的解释为什么命令是这样的,接受的答案不包括.谢谢! (2认同)

ken*_*orb 6

;(分号)或(加号)之间的区别+在于参数如何传递到 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
    
    Run Code Online (Sandbox Code Playgroud)

    以下所有参数都find被视为该命令的参数。

    该字符串{}将替换为当前正在处理的文件名。

  • using+将执行最少可能的命令(因为参数组合在一起)。它与xargs命令的工作方式非常相似,因此它将在每个命令中使用尽可能多的参数,以避免超出每行参数的最大限制。

    例子:

    $ find /etc/rc* -exec echo Arg: {} '+'
    Arg: /etc/rc.common /etc/rc.common~previous /etc/rc.local /etc/rc.netboot
    
    Run Code Online (Sandbox Code Playgroud)

    命令行是通过在末尾附加每个选定的文件名来构建的。

    {}命令中只允许出现一个 的实例。

也可以看看: