代码之家  ›  专栏  ›  技术社区  ›  Phillip

最快字符串二进制文件grep

  •  1
  • Phillip  · 技术社区  · 8 年前

    我使用以下linux shell命令来计算 二进制文件 这需要太多的时间(大约10秒);

    strings /path/to/<binary_file> | grep -c -E "word1|word2|...|wordN"
    

    我怎样才能加快这个过程?

    我试着只用 grep 命令,但找不到字,所以我必须使用 strings . 我试着加上 wc 而不是 -c ,但速度较慢。 顺便说一下,我在android环境中没有parallel命令。

    其实我还是写不出这个组合的c等价物,任何帮助都将不胜感激。

    1 回复  |  直到 8 年前
        1
  •  1
  •   xhienne    8 年前

    前言

    首先,你的命令有几个缺陷,在某些情况下会失败:

    • 它不能处理由非ascii字符(如重音字母)组成的单词,因为它们被过滤 strings 是的。不过,你可能并不想听到这样的话。

    • 如果单词是孤立的,它将丢失少于4个字符的单词。你应该用 strings -n1 一个通用的解决方案。

    • 当多个单词属于同一行文本时,它将丢失单词,因为 grep -c 数数线条,而不是文字。

    Android实现的问题 grep (从Android 8.1开始):

    • 在android上,你必须使用 grep -E 'word1|word2|...|wordN' 而不是 grep -F -e word1 -e word2 .. -e wordN 相当于,但通常要快得多。这是因为android 8中存在一个错误,使得后者无法正确计算。

    • 在android上,我不会只使用 grep -a 但是 grep -za . 在linux上,gnu grep将二进制文件中的nul(0)字符视为行尾,并且 -z 选项不仅无用,而且不可取,因为输出行也将以nul而不是换行符结束。但是android版本的表现有所不同:nul字符需要显式地作为换行符处理,否则后面的内容将被忽略;碰巧换行符仍然是用传统换行符输出的。

    限制的输出

    通过设置 -n 选择权 到你要找的最小单词的大小。例如,如果您要查找的单词都不少于7个字符,请使用 strings -n7 . 因此,您将降低进程间通信,并且 格雷普 不会费心搜索那些显然不符合模式的行。

    摆脱

    有点贵,可能没有什么好处(这取决于被过滤掉的二进制字符的数量-ymmv,请参阅下一节中的注释),甚至是有害的(请参阅前言)。你可以通过以下方式摆脱它:

    grep -F -a -o -e word1 -e word 2 ... -e wordN /path/to/binary_file \
    | wc -l
    

    因为前面提到的android的问题 格雷普 ,这是Android的版本:

    grep -z -a -o -E 'word1|word2|...|wordN' /path/to/binary_file \
    | wc -l
    

    记住,使用 grep | wc 是强制性的,因为 格雷普-C 不计算字数,只计算行数。这就是为什么 格雷普-C 在你看来要快一点,因为一旦找到一个词, 格雷普 计数+1并继续下一个输入行,可能在当前行上缺少其他单词。

    并行化

    根据核的数量,您还可以通过并行化 格雷普 学生:

    ( grep -F -a -o -e word1 -e word2 /path/to/binary_file &
      grep -F -a -o -e word3 -e word4 /path/to/binary_file
    ) | wc -l
    

    因为前面提到的android的问题 格雷普 ,这是Android的版本:

    ( grep -z -a -o -E 'word1|word2' /path/to/binary_file &
      grep -z -a -o -E 'word3|word4' /path/to/binary_file
    ) | wc -l
    

    在这里,我假设最密集的处理是由 格雷普 由于它们的过滤作用 wc 他的工作是次要的。根据搜索模式的不同,情况可能不同。同样,如果 在过滤掉二进制文件方面做得很好,最好把它作为第一条指令。YMMV公司。

    使用 tr 而不是

    可能会过滤掉大量不必要的(非ascii)字符,这确实有帮助 格雷普 处理更少的数据。你可以通过过滤掉不属于你要找的单词的每个字符来做得更进一步。例如,如果查找“word1”、“word2”和“word3”,则可以筛选出不是w、o、r、d、1、2、3的所有字符。

    如果您有权访问 tr公司 命令行工具,使用它而不是 :

    tr -c -s 'word123' '\n' < /path/to/binary_file \
    | grep -F -o -e word1 -e word2 -e word3 \
    | wc -l
    

    因为前面提到的android的问题 格雷普 ,这是Android的版本:

    tr -c -s 'word123' '\n' < /path/to/binary_file \
    | grep -E -o 'word1|word2|word3' \
    | wc -l
    

    (注意 tr公司 不适用于非ascii多字节字符,但因为您正在使用 在ascii模式下,您已经不关心这个了)

    标杆管理

    下面是在一个24mb的声音文件上做的一些测试;这个平台是我的android 8.1octacore手机。根据您的输入文件、搜索字符串和核心数,您显然会得到其他结果,但这会让您了解可能的速度改进。

    # Your original command (fixed)
    $ time strings -n1 test | grep -E 'A|B|C|D' -o | wc -l
    403380
        0m18.93s real     0m10.05s user     0m13.77s system
    
    # grep alone
    $ time grep -z -a -E 'A|B|C|D' -o test | wc -l
    403380
        0m07.03s real     0m05.26s user     0m00.04s system
    
    # Parallelized grep (x2)
    $ time ( grep -z -a -E 'A|B' -o test &
             grep -z -a -E 'C|D' -o test
           ) | wc -l
    403380
        0m03.56s real     0m03.12s user     0m00.03s system
    
    # Parallelized grep -F (x4 - one per string to search)
    $ time ( grep -z -a -F A -o test &
             grep -z -a -F B -o test &  
             grep -z -a -F C -o test &
             grep -z -a -F D -o test
           ) | wc -l 
    403380
        0m01.04s real     0m01.88s user     0m00.05s system
    
    # tr instead of string
    $ time tr -c -s 'ABCD' '\n' < test | grep -E 'A|B|C|D' -o | wc -l
    403380
        0m01.60s real     0m01.27s user     0m01.41s system
    
    # Parallelized tr + grep (x2)
    $ time ( tr -c -s 'AB' '\n' < test | grep -E 'A|B' -o &
             tr -c -s 'CD' '\n' < test | grep -E 'C|D' -o
           ) | wc -l
    403380
        0m00.95s real     0m01.23s user     0m02.20s system
    

    如您所见,在这些测试条件下,与 最后一个(和 tr公司 并并行化)。