【问题标题】:Why is find + sed search and replace way slower than grep -r为什么 find + sed 搜索和替换方式比 grep -r 慢
【发布时间】:2018-01-18 22:06:27
【问题描述】:

我正在尝试对存储库(大约 200mB,3000 个文件)进行搜索和替换,我发现与 grep 相比,它对于相同的表达式真的很慢。即使很难匹配的数量也很少(一对 100),所以替换部分不应该减慢太多。

使用的命令:

time grep -r 'home' .

real    0m0.228s
user    0m0.154s
sys     0m0.071s


time find . -type f -exec sed -i 's/home/test/g' {} \;

real    0m38.064s
user    0m8.893s
sys     0m28.552s


time find . -type f -exec sed -i 's/home/test/g' {} +

real    0m25.671s
user    0m5.654s
sys     0m19.968s


time find . -type f

real    0m0.090s
user    0m0.013s
sys     0m0.028s

这里发生了什么?有没有办法用不同的命令加速它?

【问题讨论】:

  • 您在示例中比较了苹果和橙子。
  • 对于初学者,-exec sed ... {} \; 为每个文件生成一个子shell,而grep -r 没有。这是一篇关于为什么 GNU grep 速度快的有趣文章:lists.freebsd.org/pipermail/freebsd-current/2010-August/…
  • 另外,sed -i 必须复制它修改的每个文件,grep 只是读取。
  • 但是有没有更快的替代搜索和替换?大多数情况下,我看到人们推荐 find + sed 版本
  • @BenjaminW.: 不,它不是子shell,它是sed 子进程,与shell 无关。存在显着差异。 (如果没有那个“subshel​​l”这个词,那么我相信你是正确的)

标签: bash performance unix sed grep


【解决方案1】:

缓慢的部分可能是sed 重写每个文件——它必须对每个文件都这样做,即使是那些不匹配的文件。如果大多数文件不匹配,您应该能够通过使用grep 生成匹配文件列表(您知道这很快)来加速它,然后将其提供给sed 以重写它们。

grep -r -l 'home' . | while read -r filename; do
    sed -i 's/home/test/g' "$filename"
done

grep-l 选项告诉它只打印匹配的文件名。

如果您使用的是 GNU grep,您可以通过使用 -Z 选项以空终止文件名来使其更加安全和高效;那么包含换行符的文件名不会有问题。

grep -rlZ 'home' . | xargs -0 sed -i 's/home/test/g/ {} +

【讨论】:

  • grep -rlZ ... | xargs -0 ... 这也有助于加快并行选项的速度 - unix.stackexchange.com/a/24979
  • 在我的系统 (Mac OS El Capitan) 上,-Z 表示像 zgrep 一样行事
  • 通过一些修复,您的想法效果惊人:) time grep -rlZ 'home' ferguson | xargs -0 sed -i 's/home/test/g' real 0m0.293s user 0m0.150s sys 0m0.136s (对于这个特定情况,find + sed 加速了 100 倍)
  • 我的特定用例(更大的 repo 和更复杂的正则表达式)从 20 分钟缩短到 13 秒
猜你喜欢
  • 1970-01-01
  • 2012-05-12
  • 2010-11-13
  • 1970-01-01
  • 2014-09-13
  • 2015-06-10
  • 2011-07-29
  • 1970-01-01
  • 2011-08-16
相关资源
最近更新 更多