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)
它的重点是
awk
命令仅打印第一个匹配字符串之后到第二个匹配字符串的行)zipgrep
即使在 24 核机器上有 10 个进程,这种单行运行速度也非常慢。我相信它因为zipgrep
命令而变慢,但我不够聪明,不知道如何改进它。我不知道该不该,但我有点尴尬,我的同事写了一个运行速度比这个脚本更快的java工具。如果可能的话,我想扭转这种局面。那么,有没有人知道如何在这种情况下更快地执行此命令?或者完全改进它的任何部分?
有一部分您可以轻松改进,但这并不是最慢的部分。
Run Code Online (Sandbox Code Playgroud)find /home/mydir/ -type f | sort | \ awk "/xml_20140207_000016.zip/,/xml_20140207_235938.zip/"
这有点浪费,因为它首先列出所有文件,然后对文件名进行排序并提取有趣的文件。该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 实现。
一些快速的想法;
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"
归档时间: |
|
查看次数: |
880 次 |
最近记录: |