【问题标题】:find -exec cmd {} + vs | xargs查找 -exec cmd {} + vs | xargs
【发布时间】:2018-04-24 10:30:17
【问题描述】:

对于非常大的文件集,应该使用哪个更有效?

find . -exec cmd {} +

find . | xargs cmd

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

【问题讨论】:

标签: linux unix command-line find


【解决方案1】:

速度差异将是微不足道的。

但你必须确保:

  1. 您的脚本不会假定没有 文件中将有空格、制表符等 文件名;第一个版本是 安全,第二个不安全。

  2. 您的脚本不会将以“-”开头的文件作为选项。

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

find . -exec cmd -option1 -option2 -- {} +

find . -print0 | xargs -0 cmd -option1 -option2 --

第一个版本更短更容易写,因为你可以忽略 1,但是 第二个版本更加便携和安全,因为“-exec cmd {} +”是 GNU findutils 中一个相对较新的选项(自 2005 年以来,许多正在运行的系统还没有它),它是 buggy recently。也有很多人不知道这个“-exec cmd {} +”,正如您从其他答案中看到的那样。

【讨论】:

  • -print0 也是一个 GNU find(和 GNU xargs)选项,许多非 Linux 系统都缺少该选项,因此可移植性参数无效。但是,仅使用 -print 并保留 xargs 的 -0, 非常便携。
  • 关键是如果没有-print0,如果文件有空格或制表符等,它就不起作用。这可能是一个安全漏洞,就好像有一个像“foo -o index.txt”这样的文件名。 html" 然后 -o 将被视为一个选项。在空目录中尝试:“touch -- foo\ -o\ index.html; find . | xargs cat”。你会得到:“cat: invalid option -- 'o'”
  • 他的例子是一个包含 - 的文件名。如果没有 -print0,find 会输出 ./foo -o index.html。因此,也许以 - 开头并不是什么大问题,但结果几乎没有变化,并且在多用户系统上,如果您的脚本是世界可读的,则可以提供攻击向量。
  • 关于让我在这里绊倒的事情的注释 - 使用 exec 将在找到结果时输出结果,而 xargs 似乎会等到整个目录被搜索到后再写入标准输出.如果您在大型目录中尝试此操作,并且似乎 xargs 不起作用,建议您耐心等待。
  • @Motivated without -print0 find 返回用换行符分隔的文件名,但换行符也可以是文件名的一部分,使其不明确。字节 0 不能,所以它是一个安全的分隔符。是的 - 当您无法控制其参数时,将-- 添加到支持它的命令中是一个好习惯,即使并非总是严格要求或不安全。
【解决方案2】:
find . | xargs cmd

效率更高(它运行cmd 的次数越少越好,不像exec,它为每场比赛运行一次cmd)。但是,如果文件名包含空格或时髦字符,您将遇到麻烦。

建议使用以下:

find . -print0 | xargs -0 cmd

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

【讨论】:

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

现代xargs 的版本通常支持并行管道执行。

显然,在选择 find … -exec… | xargs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-17
    • 2019-04-09
    • 2012-07-27
    • 1970-01-01
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    相关资源
    最近更新 更多