Linux上的二进制grep?

说我已经生成了以下二进制文件:

# generate file: python -c 'import sys;[sys.stdout.write(chr(i)) for i in (0,0,0,0,2,4,6,8,0,1,3,0,5,20)]' > mydata.bin # get file size in bytes stat -c '%s' mydata.bin # 14 

并说,我想要find所有零( 0x00 )的位置,使用类似grep的语法。

我能做到的最好的是:

 $ hexdump -v -e "1/1 \" %02x\n\"" mydata.bin | grep -n '00' 1: 00 2: 00 3: 00 4: 00 9: 00 12: 00 

但是,这将隐式地将原始二进制文件中的每个字节转换为grep操作的多字节ASCII表示forms; 不完全是优化的主要例子:)

有什么像Linux的二进制grep ? 也可能是支持正则expression式语法的东西,也可能是字节“字符” – 也就是说,我可以写' a(\x00*)b '之类的东西,并匹配零或多个字节出现的字节字节'a'(97)和'b'(98)之间的0

编辑:上下文是我正在一个驱动程序,我在哪里捕捉8位数据; 数据中出现了一些错误,可能是千字节到兆字节,我想检查特定的签名和它们发生的位置。 ( 到目前为止,我正在使用千字节片段,因此优化并不重要 – 但是如果我开始在兆字节长的捕获中出现一些错误,并且我需要分析这些错误,那么我的猜测是我想要更优化的东西:)。 尤其是,我希望能够“grep”作为字符的某个字节hexdump迫使我search每个字节的string

EDIT2:同样的问题,不同的论坛:) grep通过一个二进制文件的字节序列

编辑3:感谢@tchrist的回答,这里也是一个例子'grepping'和匹配,并显示结果( 虽然不完全相同的问题OP ):

 $ perl -ln0777e 'print unpack("H*",$1), "\n", pos() while /(.....\0\0\0\xCC\0\0\0.....)/g' /path/to/myfile.bin ca000000cb000000cc000000cd000000ce # Matched data (hex) 66357 # Offset (dec) 

要将匹配的数据分组为每个字节(两个hex字符),则需要为匹配string中的字节数指定“H2 H2 H2 …”; 因为我的匹配“ .....\0\0\0\xCC\0\0\0..... ”覆盖了17个字节,所以我可以在Perl中编写"H2"x17 “。 这些“H2”中的每一个都将返回一个单独的variables(如列表中所示),因此需要使用连接来在它们之间添加空格 – 最终:

 $ perl -ln0777e 'print join(" ", unpack("H2 "x17,$1)), "\n", pos() while /(.....\0\0\0\xCC\0\0\0.....)/g' /path/to/myfile.bin ca 00 00 00 cb 00 00 00 cc 00 00 00 cd 00 00 00 ce 66357 

那么..确实Perl是非常好的“二进制grepping”设施,我必须承认:)只要一个学习正确的语法:)

Solutions Collecting From Web of "Linux上的二进制grep?"

单线输入

这是一个较短的单线版本:

 % perl -ln0e 'print tell' < inputfile 

这是一个稍长的单线:

 % perl -e '($/,$\) = ("\0","\n"); print tell while <STDIN>' < inputfile 

连接这两个单线程的方法是通过编译第一个程序:

 % perl -MO=Deparse,-p -ln0e 'print tell' BEGIN { $/ = "\000"; $\ = "\n"; } LINE: while (defined(($_ = <ARGV>))) { chomp($_); print(tell); } 

程序化输入

如果你想把它放在一个文件中而不是从命令行调用它,这里有一个更明确的版本:

 #!/usr/bin/env perl use English qw[ -no_match_vars ]; $RS = "\0"; # input separator for readline, chomp $ORS = "\n"; # output separator for print while (<STDIN>) { print tell(); } 

这是真正的长版本:

 #!/usr/bin/env perl use strict; use autodie; # for perl5.10 or better use warnings qw[ FATAL all ]; use IO::Handle; IO::Handle->input_record_separator("\0"); IO::Handle->output_record_separator("\n"); binmode(STDIN); # just in case while (my $null_terminated = readline(STDIN)) { # this just *past* the null we just read: my $seek_offset = tell(STDIN); print STDOUT $seek_offset; } close(STDIN); close(STDOUT); 

单线输出

顺便说一句,创建测试输入文件,我没有使用你的大,长的Python脚本; 我只是使用了这个简单的Perl单行版本:

 % perl -e 'print 0.0.0.0.2.4.6.8.0.1.3.0.5.20' > inputfile 

你会发现,Perl经常会比Python做2-3次,完成同样的工作。 而且你不必在清晰度上妥协。 上面的一行可能会更简单吗?

程控输出

我知道我知道。 如果你还不知道这个语言,可能会更清楚:

 #!/usr/bin/env perl @values = ( 0, 0, 0, 0, 2, 4, 6, 8, 0, 1, 3, 0, 5, 20, ); print pack("C*", @values); 

尽管这也起作用:

 print chr for @values; 

像那样

 print map { chr } @values; 

尽管对于那些喜欢所有事情的人来说,所有的事情都是严谨而谨慎的,但是这可能更像你所看到的:

 #!/usr/bin/env perl use strict; use warnings qw[ FATAL all ]; use autodie; binmode(STDOUT); my @octet_list = ( 0, 0, 0, 0, 2, 4, 6, 8, 0, 1, 3, 0, 5, 20, ); my $binary = pack("C*", @octet_list); print STDOUT $binary; close(STDOUT); 

TMTOWTDI

Perl支持多种方式来执行操作,以便您可以选择最适合的方式。 如果这是我计划作为学校或工作项目检查的东西,我肯定会选择更长,更仔细的版本 – 或者至少在我使用单线程的时候在shell脚本中留下评论。

你可以在你自己的系统上找到Perl的文档。 只要输入

 % man perl % man perlrun % man perlvar % man perlfunc 

等你的shell提示符下。 如果你想在Web上使用漂亮的版本, 请从http://perldoc.perl.org获取perl , perlrun , perlvar和perlfunc的联机帮助页。

这似乎为我工作:

 grep --only-matching --byte-offset --binary --text --perl-regexp "<\x-hex pattern>" <file> 

简写:

 grep -obUaP "<\x-hex pattern>" <file> 

例:

 grep -obUaP "\x01\x02" /bin/grep 

输出( Cygwin二进制):

 153: <\x01\x02> 33210: <\x01\x02> 53453: <\x01\x02> 

所以你可以再次grep这个来提取偏移量。 但是不要忘记再次使用二进制模式。

其他人似乎也同样沮丧,并写了自己的工具来做到这一点(或至少类似): bgrep 。

bbe程序是二进制文件的sed- like编辑器。 见文件 。

bbe示例:

 bbe -b "/\x00\x00\xCC\x00\x00\x00/:17" -s -e "F d" -e "ph" -e "A \n" mydata.bin 11:x00 x00 xcc x00 x00 x00 xcd x00 x00 x00 xce 

说明

 -b search pattern between //. each 2 byte begin with \x (hexa notation). -b works like this /pattern/:length (in byte) after matched pattern -s similar to 'grep -o' suppress unmatched output -e similar to 'sed -e' give commands -e 'F d' display offsets before each result here: '11:' -e 'ph' print results in hexadecimal notation -e 'A \n' append end-of-line to each result 

你也可以管它sed有一个更清洁的输出:

 bbe -b "/\x00\x00\xCC\x00\x00\x00/:17" -s -e "F d" -e "ph" -e "A \n" mydata.bin | sed -e 's/x//g' 11:00 00 cc 00 00 00 cd 00 00 00 ce 

你从EDIT3的Perl的解决方案给我一个大文件“内存不足”的错误。

bgrep也是一样的问题。

唯一的缺点是,我不知道如何打印匹配模式之前的上下文。

一种只用grep解决你的直接问题的方法是创建一个包含单个空字节的文件。 之后, grep -abo -f null_byte_file target_file将产生以下输出。

 0:
 1:
 2:
 3:
 8:
 11:

当然,每个字节偏移量都是由“-b”所要求的,后跟一个空字节,如“-o”

我会第一个提倡perl,但在这种情况下,不需要引入大家庭。

那么grep -a呢? 不知道它是如何工作在真正的二进制文件,但它适用于操作系统认为是二进制文本文件。