有没有办法让这个单线更快?

fif*_*ine 7 grep bash xargs awk shell-script

语境

我有一个包含数千个 zip 文件的目录,这些文件在表单中注明日期YYYYMMDD_hhmmss.zip,每个大约 300K。在每个 zip 文件中大约有 400 个 xml 文件,每个大约 3K。

问题

我需要能够在 zip 文件的日期范围内搜索和找到给定的字符串。

当前(尽管平庸)的解决方案

我有以下单线

find /home/mydir/ -type f | sort | \
awk "/xml_20140207_000016.zip/,/xml_20140207_235938.zip/" | \
xargs -n 1 -P 10 zipgrep "my search string"
Run Code Online (Sandbox Code Playgroud)

它的重点是

  1. 列出我的千文件目录中的所有文件
  2. 对这个文件列表进行排序
  3. 根据给定日期检索一系列文件(此awk命令仅打印第一个匹配字符串之后到第二个匹配字符串的行)
  4. 将对应于单个文件的结果的每一行传递给 zipgrep

问题

即使在 24 核机器上有 10 个进程,这种单行运行速度也非常慢。我相信它因为zipgrep命令而变慢,但我不够聪明,不知道如何改进它。我不知道该不该,但我有点尴尬,我的同事写了一个运行速度比这个脚本更快的java工具。如果可能的话,我想扭转这种局面。那么,有没有人知道如何在这种情况下更快地执行此命令?或者完全改进它的任何部分?

Gil*_*il' 7

有一部分您可以轻松改进,但这并不是最慢的部分。

find /home/mydir/ -type f | sort | \
awk "/xml_20140207_000016.zip/,/xml_20140207_235938.zip/"
Run Code Online (Sandbox Code Playgroud)

这有点浪费,因为它首先列出所有文件,然后对文件名进行排序并提取有趣的文件。该find命令已运行到完成分拣,然后才能开始。

首先只列出感兴趣的文件会更快,或者至少列出尽可能小的超集。如果您需要更细粒度的名称过滤器find,请输入 awk,但不要排序:awk 和其他逐行过滤器可以逐行处理行,但 sort 需要完整的输入。

find /home/mydir/ -name 'xml_20140207_??????.zip' -type f | \
awk 'match($0, /_[0-9]*.zip$/) &&
     (time = substr($0, RSTART+1, RLENGTH-5)) &&
     time >= 16 && time <= 235938' |
xargs -n 1 -P 10 zipgrep "my search string"
Run Code Online (Sandbox Code Playgroud)

最明显次优的部分是 zipgrep。由于 shell 编程的限制,这里没有简单的方法来提高性能。zipgrep 脚本通过列出存档中的文件名并grep逐个调用每个文件的内容来运行。这意味着 zip 存档会为每个文件一次又一次地解析。Java 程序(或 Perl、Python 或 Ruby 等)可以通过只处理一次文件来避免这种情况。

如果你想坚持 shell 编程,你可以尝试挂载每个 zip,而不是使用 zipgrep。

… | xargs -n1 -P2 sh -c '
    mkdir "mnt$$-$1";
    fuse-zip "$1" "mnt$$-$1";
    grep -R "$0" "mnt$$-$1"
    fusermount -u "mnt$$-$1"
' "my search string"
Run Code Online (Sandbox Code Playgroud)

请注意,并行性不会对您有多大帮助:大多数设置的限制因素将是磁盘 I/O 带宽,而不是 CPU 时间。

我没有对任何东西进行基准测试,但我认为最大的改进地方是在更强大的语言中使用 zipgrep 实现。


x86*_*tux 6

一些快速的想法;

  • 如果所有文件都在一个目录中,则可以去掉 find
  • 您的文件名约定按日期对自身进行排序,因此您也不需要该sort
  • 有了这两部分,如果日期范围已知,您可以使用简单的文件名 glob 而不是 awk。例如(假设您的外壳是bash):

    • 一天的所有文件

      echo xml_20140207_*.zip | xargs -n 1 -P 10 zipgrep "my search string"

    • 在 2014 年 2 月 7 日或 2 月 10 日 15:00 到 18:00 之间创建的文件:

      echo xml_201402{07,10}_1{5..7}*.zip | xargs -n 1 -P 10 zipgrep "my search string"