find -exec cmd {} + vs | xargs的

dog*_*ane 111 unix linux command-line find

哪一个对于一大堆文件更有效并应该使用?

find . -exec cmd {} +
Run Code Online (Sandbox Code Playgroud)

要么

find . | xargs cmd
Run Code Online (Sandbox Code Playgroud)

(假设文件名中没有有趣的字符)

Tom*_*zky 103

速度差异无关紧要.

但你必须确保:

  1. 您的脚本不会假定文件名中没有文件的空格,标签等; 第一个版本是安全的,第二个版本不是.

  2. 您的脚本不会将以" -" 开头的文件视为选项.

所以你的代码应该是这样的:

find . -exec cmd -option1 -option2 -- {} +
Run Code Online (Sandbox Code Playgroud)

要么

find . -print0 | xargs -0 cmd -option1 -option2 --
Run Code Online (Sandbox Code Playgroud)

第一个版本更短,更容易编写,因为你可以忽略1,但第二个版本更便携和安全,因为" -exec cmd {} +"是GNU findutils中相对较新的选项(自2005年以来,许多正在运行的系统还没有它)最近辆车很快.-exec cmd {} +从其他答案可以看出,很多人都不知道这个" ".

  • 关键是没有-print0,如果有一个带有空格或制表符等的文件,它就不起作用.这可能是一个安全漏洞,好像有一个像"foo -o index.html"这样的文件名,那么-o将被处理作为一种选择.尝试在空目录中:"touch - foo\-o\index.html; find.| xargs cat".你会得到:"猫:无效选项 - 'o'" (7认同)
  • -print0也是一个GNU find(和GNU xargs)选项,很多非Linux系统都缺少这个选项,因此可移植性参数没有那么有效.然而,使用just -print并将x-off保留为xargs,*非常便携. (4认同)
  • 他的例子是一个包含 - 的文件名.如果没有-print0,find会吐出./foo -o index.html.所以也许从一个开始 - 并不是什么大问题,但结果几乎没有改变,并且在多用户系统上,如果你的脚本是世界可读的,它可以提供攻击向量. (2认同)
  • 关于让我在这里绊倒的东西的注意事项 - 使用`exec`将在找到结果时输出结果,看来`xargs`似乎要等到整个目录被搜索到写入stdout之前.如果你在一个大目录上尝试这个,并且似乎`xargs`不起作用,建议耐心. (2认同)
  • @Motivated 如果没有 `-print0` find 会返回用换行符分隔的文件名,但换行符也可以是文件名的一部分,使其不明确。字节 0 不能,所以它是一个安全的分隔符。是的 - 当您无法控制它的参数时,向支持它的命令添加 `--` 是一个很好的做法,即使并不总是严格要求或不安全。 (2认同)

ASk*_*ASk 8

find . | xargs cmd
Run Code Online (Sandbox Code Playgroud)

效率更高(它运行的cmd次数尽可能少,不像每次匹配exec运行cmd一次).但是,如果文件名包含空格或时髦字符,则会遇到麻烦.

建议使用以下内容:

find . -print0 | xargs -0 cmd
Run Code Online (Sandbox Code Playgroud)

这将工作,即使文件名包含时髦的字符(-print0使find打印NUL终止匹配,-0使得xargs期望这种格式.)

  • 这不是"find.-exec cmd {} \;" 但是"找到.-exec cmd {} +".后者不会一次运行一个文件. (28认同)
  • 请注意,如果没有(或只有少数)匹配文件,`xargs`方法实际上要慢得多,而且`cmd`对每个文件没有太多要做.例如,当在空目录中运行时,`xargs`版本将至少花费两倍的时间,因为必须启动两个进程而不是一个进程.(是的,差异通常在*nix上难以察觉,但在循环中它可能很重要;或者,在Windows上尝试一段时间......) (2认同)