【发布时间】:2011-09-23 01:05:27
【问题描述】:
我正在尝试从二进制文件中删除 ANSI 字符串“stringstart”和“stringend”之间的部分。是否可以使用 sed 或 perl -pe 来做到这一点?
我正在考虑一些正则表达式解决方案,但我不知道如何编写它,也不知道正则表达式如何与二进制文件配合使用。
【问题讨论】:
我正在尝试从二进制文件中删除 ANSI 字符串“stringstart”和“stringend”之间的部分。是否可以使用 sed 或 perl -pe 来做到这一点?
我正在考虑一些正则表达式解决方案,但我不知道如何编写它,也不知道正则表达式如何与二进制文件配合使用。
【问题讨论】:
您可以执行一个正则表达式来删除 [] 内的 ^ 之后未定义的所有字符。例如
cp /bin/ls ./binfile
file binfile
binfile: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
在上面做 perl 馅饼:
perl -pi -e 's/[^[a-zA-Z0-9_+\n]//g' binfile
然后再看二进制文件:
file binfile
binfile: ASCII text, with very long lines
您显然必须在该命令中添加更多内容,因为它会删除其他几个可能是有效的字符。但这应该可以帮助您入门。
【讨论】:
sed 是为处理文本文件而不是二进制文件而设计的,尽管这些天来,这种区别通常不如以前那么重要。最大的问题是文本文件不包含零字节(值为 0 的字节)而二进制文件包含,并且许多 C 字符串处理函数在第一个零字节处停止。 sed 还读取由换行符标记的“行”。结果,二进制文件可能会以长行结束。最后,不能保证字符串开始和结束标记相对于换行符的相对位置。所有这些特征使得sed 不如 Perl 更适合这项工作。
在 Perl 中,我非常想将文件放入内存中,使用适当的正则表达式从内存映像中删除数据,然后将结果写回适当的位置。
perl -e 'local($/); $data = <>; $data =~ s/stringstart(.*?)stringend//gms; print $data'
现已测试 - 使用以下方法创建的测试数据:
#!/usr/bin/env perl
use strict;
use warnings;
sub full_set
{
foreach my $i (0..255) { printf "%c", $i; }
}
sub random_set
{
my($n) = @_;
foreach my $i (0..$n) { printf "%c", int(rand(255)); }
}
full_set;
random_set(1024);
printf("stringstart");
full_set;
random_set(512);
full_set;
printf("stringend");
random_set(256);
脚本从输入中删除 1045 个字符 - 对应于 'stringstart', 'stringend' (20) + 2 * 256 + 513(因为 random_set(512) 打印 513 个字符)。
请注意,主脚本会一次将所有文件读入内存。如果您希望它一次处理一个文件,则必须更加努力;它可能不再是单线了。
【讨论】:
.*?。否则它只会执行一次替换,从第一个 stringstart 到最后一个 stringend。如果只有一对 start/end 预期,那么正则表达式当然没问题——那么你可以删除 g 修饰符。
zero bytes 是指空字节吗?
\0 上解析参数 :)
另一种方法:
perl -pi -we'BEGIN{$/="stringend"} chomp and s/stringstart.*//s' your_binary_file
【讨论】: