`grep` 处理一个字符串的所有文件需要很长时间

Win*_*nix 8 performance command-line search grep

grep 命令选项

我想在我的整个驱动器中搜索一个字符串。按照我使用的Stack Overflow 中接受的答案:

sudo time grep -rnw '/' -e 'Sony 50"'
Run Code Online (Sandbox Code Playgroud)

在最快的 PCIe NVMe M.2 SSD 之一上处理 20 GB 数据需要53 小时;三星 Pro 960。

grep 输出日志

grep处理某些文件时,它会生成错误消息。这些可以通过附加2>/dev/null到命令来抑制。然而,这些错误会反馈正在取得的进展。一些示例输出(它不会全部适合)如下:

Binary file /home/Me/.config/google-chrome/Default/Sync Data/SyncData.sqlite3 matches
grep: /sys/kernel/security/ima/policy: Permission denied
grep: /sys/kernel/slab/:dt-0000008/alloc_calls: Function not implemented
grep: /sys/kernel/slab/:dt-0000008/free_calls: Function not implemented
      (... SNIP ... 12 hours later PID 882 processed below...)
grep: /proc/882/task/922/attr/sockcreate: Invalid argument
grep: /proc/882/task/923/mem: Input/output error
      (... SNIP ... 24 hours later PID 2954 below...)
grep: /proc/2598/attr/sockcreate: Invalid argument
grep: /proc/2954/task/2954/mem: Input/output error
      (... SNIP ... 42 hours later PID 4396 below...)
grep: /proc/4389/attr/sockcreate: Invalid argument
grep: /proc/4396/task/4396/mem: Input/output error
      (... SNIP ... After 53 hours `grep` finally finishes...)
grep: /run/user/1000/gvfs: Permission denied
Command exited with non-zero status 2
97355.34user 83223.12system 53:07:40elapsed 94%CPU (0avgtext+0avgdata 31116maxresident)k
593910020inputs+0outputs (1major+10731minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

grep 给人的印象是它被冻结了

有时我以为grep是卡住了,因为屏幕一个小时没有更新,硬盘灯也不怎么闪。然而,Conky 告诉我它仍在运行并在单核上占用 100% 的 CPU,如这个 GIF 所示

在Linux (Ubuntu 16.04.3 LTS) 分区上使用的 43.8 GiB 中的19.5 GiB 中,内核使用了该空间的一半,即10 GB。下载和测试内核是我的消遣。


这个测试花了我周末和周一的大部分时间来完成。

我怎样才能加快速度grep并仍然得到我正在寻找的东西?

Win*_*nix 16

排除虚拟文件系统

查看示例输出日志,我们看到搜索中包含虚拟文件系统,这是不必要的时间浪费。使用--exclude-dir选项从搜索中删除这些和其他目录。例如:

sudo time grep -rnw --exclude-dir={boot,dev,lib,media,mnt,proc,root,run,sys,/tmp,tmpfs,var} '/' -e 'Sony 50"'
Run Code Online (Sandbox Code Playgroud)

grep解析/proc目录链被白白看着所有的进程的ID这需要一天以上的时间在我的情况。

此外,在处理时,/mnt它会不必要地查看已安装的 Windows NTFS 驱动器和 USB。

/media 包含 CD/DVD 驱动器和外部 USB 驱动器。

输出:

$ sudo time grep -rnw --exclude-dir={boot,dev,lib,media,mnt,proc,root,run,sys,/tmp,tmpfs,var} '/' -e 'Sony 50"'
Binary file /home/Me/.config/google-chrome/Default/Sync Data/SyncData.sqlite3 matches
11.35user 13.83system 0:56.35elapsed 44%CPU (0avgtext+0avgdata 8480maxresident)k
17369032inputs+0outputs (0major+1620minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

那里是56 秒而不是50 小时

请注意,如果您usr从搜索中排除(在我的情况下包含 6.5 GB 的文件),则只需 8 秒:

4.48user 1.80system 0:08.75elapsed 71%CPU (0avgtext+0avgdata 6012maxresident)k
13008964inputs+0outputs (0major+1180minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

有趣的笔记

将系统目录排除在外似乎可以grep更好地跟踪,并且它永远不会在单核上达到 100% CPU。加上硬盘灯不断闪烁,所以你知道grep它真的在工作,而不是“在圈子里思考”。

如果您没有前缀tmp/那么它将忽略任何包含tmp例如/home/Me/tmp. 如果您使用 --exclude-dir/tmp则将/home/Me/tmp搜索您的目录。

另一方面,如果您sys使用/then前缀,则会/sys搜索目录并报告错误。对于 也是如此/proc。所以你必须使用sys,proc而不是前缀/. 我测试的其他系统目录也是如此。

创建别名 grepall

考虑在 in 中设置别名,~/.bashrc这样您就不必--exclude-dir每次都键入参数列表:

alias grepall="grep --exclude-dir={boot,dev,lib,media,mnt,proc,root,run,sys,/tmp,tmpfs,var}"
Run Code Online (Sandbox Code Playgroud)

详细的时间细分

本节细分了通过将目录增量添加到--exclude-dir参数列表中节省了多少时间:

  • /proc/sys节省52 小时
  • /media节省3 分钟
  • /mnt节省21 分钟
  • /usr/src(通过指定src)节省53 秒
  • /lib/modules(通过指定modules)节省39 秒

排除/proc/sys目录

/proc/sys目录是最耗时,最无用的搜索和生成的大多数错误。这是“无用的”,因为这两个目录是在运行时动态创建的,并且不包含您想要的永久文件grep

通过排除它们可以节省大量时间:

$ sudo time grep -rnw --exclude-dir={proc,sys} '/' -e 'Garbage 098jfsd'
/var/log/auth.log:4653:Feb 16 17:46:20 alien sudo:     rick : TTY=pts/18 ; PWD=/home/rick/Downloads ; USER=root ; COMMAND=/usr/bin/time grep -rnw --exclude-dir=proc --exclude-dir=sys / -e Garbage 098jfsd
Binary file /var/log/journal/d7b25a27fe064cadb75a2f2f6ca7764e/system.journal matches
grep: /media/rick/S3A6550D005/hiberfil.sys: Input/output error
      (... SNIP ...)
grep: /media/rick/S3A6550D005/winproductkey: Input/output error
grep: /run/user/1000/gvfs: Permission denied
Command exited with non-zero status 2
422.43user 112.91system 26:59.03elapsed 33%CPU (0avgtext+0avgdata 31152maxresident)k
379671064inputs+0outputs (1major+10738minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

这次只用了27 分钟,节省了超过52 小时

不过还是有错误。在/var目录中,这也是运行时创建的“虚拟目录”。在/run其中包含一个Android手机和目录/media包含现在连接到USB外部硬盘盒旧破碎笔记本硬盘目录。

添加/media到排除列表

/media目录包含一个通过 USB 3.0 端口连接的旧笔记本电脑驱动器。Smartctl 每天报告驱动器上的错误并且没有我们要查找的文件。我们将排除它以节省时间并减少错误消息:

$ sudo time grep -rnw --exclude-dir={proc,sys,media} '/' -e 'Garbage 654asdf'
/var/log/auth.log:4664:Feb 16 18:26:27 alien sudo:     rick : TTY=pts/18 ; PWD=/home/rick/Downloads ; USER=root ; COMMAND=/usr/bin/time grep -rnw --exclude-dir=proc --exclude-dir=sys --exclude-dir=media / -e Garbage 654asdf
Binary file /var/log/journal/d7b25a27fe064cadb75a2f2f6ca7764e/system.journal matches
grep: /run/user/1000/gvfs: Permission denied
Command exited with non-zero status 2
405.51user 105.38system 23:26.89elapsed 36%CPU (0avgtext+0avgdata 30908maxresident)k
365800875inputs+0outputs (0major+10961minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

排除通过 USB 3.0 外壳连接的故障硬盘仅节省了 3 分钟,但减少了错误消息。

添加/mnt(Windows NTFS 分区)以排除列表

/mnt目录包含:

  • 具有 105 GiB 数据的 SSD 上的两个 NTFS Windows 10 分区(C:E:
  • D:硬盘上的一个 NTFS Windows 10 分区 ( ) 具有 42 GiB 数据

在 Windows 中没有任何兴趣,因此我们将排除/mnt以节省时间:

$ ll /mnt
total 44
drwxr-xr-x  5 root root  4096 Nov 12 07:19 ./
drwxr-xr-x 27 root root  4096 Feb 15 20:43 ../
drwxrwxrwx  1 root root  8192 Dec 30 14:00 c/
drwxrwxrwx  1 root root  8192 Dec 30 14:31 d/
drwxrwxrwx  1 root root 20480 Jan  1 13:22 e/

$ sudo time grep -rnw --exclude-dir={proc,sys,media,mnt} '/' -e 'Garbage zx5cv7er'
/var/log/auth.log:5093:Feb 17 10:31:44 alien sudo:     rick : TTY=pts/18 ; PWD=/home/rick/Downloads ; USER=root ; COMMAND=/usr/bin/time grep -rnw --exclude-dir=proc --exclude-dir=sys --exclude-dir=media --exclude-dir=mnt / -e Garbage zx5cv7er
Binary file /var/log/journal/d7b25a27fe064cadb75a2f2f6ca7764e/system.journal matches
grep: /run/user/1000/gvfs: Permission denied
Command exited with non-zero status 2
51.50user 23.28system 2:08.85elapsed 58%CPU (0avgtext+0avgdata 15800maxresident)k
39866258inputs+0outputs (0major+6059minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

现在grep只需要 2 分 8 秒。通过排除具有 147 Gib 程序和数据的 Windows 10 分区可节省 21.5 分钟!

添加/usr/srcLinux 标头以排除列表

/usr/src目录包含 Linux Headers 源代码。就我而言,手动安装了 20 多个内核,这需要相当大的空间。虽然使用的参数是指定目录src

$ du -h -s /usr/src
3.2G    /usr/src

$ sudo time grep -rnw --exclude-dir={proc,sys,media,mnt,src} '/' -e 'Garbage z5cv7er'
/var/log/auth.log:5096:Feb 17 10:34:28 alien sudo:     rick : TTY=pts/18 ; PWD=/home/rick/Downloads ; USER=root ; COMMAND=/usr/bin/time grep -rnw --exclude-dir=proc --exclude-dir=sys --exclude-dir=media --exclude-dir=mnt --exclude-dir=src / -e Garbage z5cv7er
Binary file /var/log/journal/d7b25a27fe064cadb75a2f2f6ca7764e/system.journal matches
grep: /run/user/1000/gvfs: Permission denied
Command exited with non-zero status 2
44.21user 8.54system 1:15.51elapsed 69%CPU (0avgtext+0avgdata 15864maxresident)k
33754180inputs+0outputs (0major+6062minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

现在 grep 只需要 1 分 15 秒。/usr/src通过src--exclude-dir列表上指定来排除可节省 53 秒。

添加/lib/modules内核模块以排除列表

/lib/modules目录包含已编译的内核模块。虽然使用的参数是指定目录modules

$ du -h -d1 /lib/modules
285M    /lib/modules/4.14.18-041418-generic
282M    /lib/modules/4.14.14-041414-generic
     (... SNIP ...)
228M    /lib/modules/4.9.76-040976-generic
6.0G    /lib/modules

$ sudo time grep -rnw --exclude-dir={proc,sys,media,mnt,src,modules} '/' -e 'Garbage 1cv7fer'
/var/log/auth.log:5117:Feb 17 11:07:41 alien sudo:     rick : TTY=pts/18 ; PWD=/home/rick/Downloads ; USER=root ; COMMAND=/usr/bin/time grep -rnw --exclude-dir=proc --exclude-dir=sys --exclude-dir=media --exclude-dir=mnt --exclude-dir=src --exclude-dir=modules / -e Garbage 1cv7fer
Binary file /var/log/journal/d7b25a27fe064cadb75a2f2f6ca7764e/system.journal matches
grep: /run/user/1000/gvfs: Permission denied
Command exited with non-zero status 2
19.22user 5.84system 0:35.61elapsed 70%CPU (0avgtext+0avgdata 15600maxresident)k
22111388inputs+0outputs (0major+6059minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

通过跳过 6 GB 的内核模块,我们的grep时间是 36 秒。/lib/modules通过modules--exclude-dir参数中指定来添加可节省 39 秒。

杂项目录

其他目录的汇总列表:

  • /boot 节省了 3 秒(但我的特别大)
  • /dev 节省 3 秒
  • /run 节省 4 秒
  • /var 节省 8 秒

  • 请注意,`--exclude-dir=tmp` 将导致目录树中任何位置的任何 `tmp` 目录被排除。所以我宁愿建议从根目录中明确列出要 grepped 的 _are_ 目录,例如 `grep -r pattern /bin /etc /home ...`。 (4认同)