当前位置: 首页 > 知识库问答 >
问题:

使用grep从二进制文件中提取非常特定的字符串

冷善
2023-03-14

我有一个很大的二进制文件。我想从中提取某些字符串并将它们复制到一个新的文本文件中。

例如,在:

D-wM-^?^@^@^@^@^@^@^@^Y^@^@^@^@^@^@^@M-lM-FM-MM-[o@^B^@M-lM-FM MM-[o@^B^@^@^@^@^@E7cacscKLrrok9bwC3Z64NTnZM-^G

我想取数字“7”(在@^@^@e之后),以及它之后的每个字符都停在Z(忽略M-^G)。

不幸的是,我对grep、sed等的知识并没有扩展到这个层次。有人能提出一个可行的方法来达到这个目的吗?

cat-v filename grep[7][A-Z,A-Z]将显示所有带有“7”后跟字母的字符串,但这并不多。

谢谢你。

我想检查一个字符串的结尾,如果它以m-结尾,则grep后面的另一个字符串(中间有垃圾)。如果字符串没有以m-结尾,那么我不希望它被复制(更别提任何其他字符串了)。

所以我想要的是:

grep-a-po“7[[:alnum:]]+(?=m-)”file_name如果结尾是m-grep-a-po“5x[[:alnum:]]+(?=\^)”file_name复制以5x开头、以^结尾的字符串。

在本例中:

D-wM-^?^@^@^@^@^@^@^@^Y^@^@^@^@^@^@^@M-lM-FM-MM-[o@^B^@M-lM-FM MM-[o@^B^@^@^@^@^@E7cacscKLrrok9bwC3Z64NTnZM-^GwM-^?^@^@^@^@^@^@^@^Y^@^@^@^@^@^@^@M-lM-FM-MM-[o@^B^@M-lM5x8w09qewqlkcklwnlkewflewfiewjfoewnflwenfwlkfwelk^89038432nowefe

其结果将是:

7cacscKLrrok9bwC3Z64NTnZ
5x8w09qewqlkcklwnlkewflewfiewjfoewnflwenfwlkfwelk

但是,如果结尾不是m-(更准确地说,如果结尾是^s),则不要尝试第二个grep并且完全不记录任何内容。

D-wM-^?^@^@^@^@^@^@^@^Y^@^@^@^@^@^@^@M-lM-FM-MM-[o@^B^@M-lM-FM MM-[o@^B^@^@^@^@^@E7cacscKLrrok9bwC3Z64NTnZ^SGwM-^?^@^@^@^@^@^@^@^Y^@^@^@^@^@^@^@M-lM-FM-MM-[o@^B^@M-lM5x8w09qewqlkcklwnlkewflewfiewjfoewnflwenfwlkfwelk^89038432nowefe

grep是正确的工具吗?Grep一个文件,如果Grep命令中的条件是'yes',则发出另一个Grep命令,但如果条件是'no',则不执行任何操作。

再次感谢。

我注意到一个附加修改。

如何将5x更改为5x6x

D-wM-^?^@^@^@^@^@^@^@^Y^@^@^@^@^@^@^@M-lM-FM-MM-[o@^B^@M-lM-FM MM-[o@^B^@^@^@^@^@E7cacscKLrrok9bwC3Z64NTnZM-^GwM-^?^@^@^@^@^@^@^@^Y^@^@^@^@^@^@^@M-lM-FM-MM-[o@^B^@M-lM5x8w09qewqlkcklwnlkewflewfiewjfoewnflwenfwlkfwelk^89038432nowefe
D-wM-^?^@^@^@^@^@^@^@^Y^@^@^@^@^@^@^@M-lM-FM-MM-[o@^B^@M-lM-FM MM-[o@^B^@^@^@^@^@E7AAAAAscKLrrok9bwC3Z64NTnZM-^GwM-^?^@^@^@^@^@^@^@^Y^@^@^@^@^@^@^@M-lM-FM-MM-[o@^B^@M-lM6x8w09qewqlkcklwnlkewflewfiewjfoewnflwenfwlkfwelk^89038432nowefe

在本例中,期望的结果是:

7cacscKLrrok9bwC3Z64NTnZ
5x8w09qewqlkcklwnlkewflewfiewjfoewnflwenfwlkfwelk
7AAAAAscKLrrok9bwC3Z64NTnZ
6x8w09qewqlkcklwnlkewflewfiewjfoewnflwenfwlkfwelk

3月09日更新:

我需要二进制文件中的两个字符串。

第一个字符串将始终以1开头。

第一个字符串将以字母或数字结尾。下一个字母将始终是小写k。我不想要这个k字符。

第二个字符串的结尾将采用以下两种形式之一:a)以空格结尾,然后以小写显示第一个字符串的前三个字符,后跟)b)以^K结尾,然后以小写显示第一个字符串的前三个字符。

例如:

<代码>1PPPSX9YPAR8RVS75TJYWZQ3EO8PGWBCKB4M4ZT7YG042KIDYUE82E893HY ppp)

应该是:

1pppsx9ypar8rvs75tjywzq3eo8pgwbcb4m4zt7yg042kidyue82e893hy-删除k和空格,然后删除ppp

例如:

1ZZZSX9YPKAR8RVS75TJYWZQ3EO8PGWBCA4M4ZT7YG042KIDYUE82E893HY-删除第二个K^KZZZ

在第二个示例中,我们看到第一个k是第一个字符串的一部分。分解第一个和第二个字符串的是A之前的K

希望有一位超级grep专家能帮上忙!多谢!

共有1个答案

袁玮
2023-03-14

如果您的grep支持-p选项,请尝试:

grep -a -Po "7[[:alnum:]]+(?=M-)" file
  • -a选项强制grep将输入作为文本文件读取。
  • -p选项启用与Perl兼容的正则表达式。
  • -o选项告诉grep只打印匹配的子字符串。
  • 模式(?=m-)是一个零宽度的前瞻断言(在Perl中引入),但不包括在结果中。

或者,您也可以使用sed:

sed 's/M-/\n/g' file | sed -n 's/.*\(7[[:alnum:]]\+\).*/\1/p'
  • 第一个sed命令通过用换行符替换子字符串m-来将输入文件拆分为多行。它有两个好处:中断行以允许使用sed进行多个匹配,并从输入中排除不必要的部分m-
  • 下一个sed命令从输入中提取所需的模式。
sed 's/M-/\'$'\n''/g' file | sed -n 's/.*\(7[[:alnum:]]\+\).*/\1/p'

[UPDATE]
(该需求已由OP更新,以下是根据该需求提供的解决方案。)

让我假设以7开头、以M-结尾的字符串后面总是跟一个以5x开头、以^(ascii插入符号)结尾且中间有垃圾的字符串(不多也不少于一个)。
那么请尝试以下操作:

grep -aPo "7[[:alnum:]]+M-.*?5x[[:alnum:]]+\^" file | grep -aPo "7[[:alnum:]]+(?=M-)|5x[[:alnum:]]+(?=\^)"
  • 它分两个步骤(两个级联的grep)执行任务。
  • 第一个grep将输入数据缩小到候选子字符串中,该子字符串将包括所需的两个序列和介于这两个序列之间的垃圾。
  • 中间的正则表达式.*?匹配除换行符以外的任何(ascii或二进制)字符。尾随的启用最短匹配,这避免了由于regex的贪婪性质而导致的溢出。正则表达式用于匹配介于两者之间的垃圾。
  • 第二个grep包括两个regex并用管道表示逻辑。然后提取两个所需序列。

grep解决方案的一个潜在问题是,grep是面向行的命令,不能在匹配的字符串中包含换行符。如果在between中包含了换行符(我不确定可能性),则上述解决方案将失败。作为一种解决办法,perl将提供对二进制数据的灵活操作。

perl -0777 -ne '
    while (/(7[[:alnum:]]+)M-.*?(5x[[:alnum:]]+)\^/sg) {
        printf("%s\n%s\n", $1, $2);
    }
' file
  • regex与grep的regex基本相同,因为grep-p选项表示与Perl兼容。
  • 它可以同时捕获变量$1$2中的多个模式,因此只要一个正则表达式就足够了。
  • perl命令的-0777选项告诉perl一次发出所有数据的声音。
  • regex末尾的s选项使点与换行符匹配。
  • G选项启用全局(多重)匹配。

[UPDATE2]
为了使正则表达式匹配5x6x,请将5x替换为(56)x
即:

grep -aPo "7[[:alnum:]]+M-.*?(5|6)x[[:alnum:]]+\^" file | grep -aPo "7[[:alnum:]]+(?=M-)|(5|6)x[[:alnum:]]+(?=\^)"

如前所述,管道表示运算符在计算中的优先级最低,因此在本例中需要将它们用括号括起来。

如果可能出现5或6以外的任何其他数字,则使用[[:digit:]]安全,它与0和9之间的任何一个数字匹配:

grep -aPo "7[[:alnum:]]+M-.*?[[:digit:]]x[[:alnum:]]+\^" file | grep -aPo "7[[:alnum:]]+(?=M-)|[[:digit:]]x[[:alnum:]]+(?=\^)"

[UPDATE3]
(3月9日回答OP的要求)

让我从perl代码开始,它的regex相对更容易解释。

perl -0777 -ne 'while (/(1(.{3}).+)k([AB].*)[\013 ]\2/g){print "$1 $3\n"}' file

输出:

1pppsx9YPar8Rvs75tJYWZq3eo8Pgwbc B4m4zT7Yg042KIDYUE82e893hY
1zzzsx9YPkr8Rvs75tJYWZq3eo8Pgwbc A2m4zT7Yg042KIDYUE82e893hY
(1(.{3}).+)k([AB].*)[\013 ]\2
(                  start of the 1st capture group referred by $1 later
 1                 literal "1"
  (                start of the 2nd capture group referred by \2 later
   .{3}            a sequence of the identical three characters such as ppp or zzz
       )           end of the 2nd capture group
        .+         followed by any characters with "greedy" match which may include the 1st "k"
          )        end of the 1st capture group
           k       literal "k"
(                  start of the 3rd capture group referred by $3 later
 [AB].*            the character "A" or "B" followed by any characters
       )           end of the 3rd capture group
        [\013 ]    followed by ^K or a whitespace
               \2  followed by the capture group 2 previously assigned
grep -Po "(1(.{3}).+)(?=k([AB].*)[\013 ]\2)" file
grep -Po "(1(.{3}).+)k\K([AB].*)(?=[\013 ]\2)" file
1pppsx9YPar8Rvs75tJYWZq3eo8Pgwbc
1zzzsx9YPkr8Rvs75tJYWZq3eo8Pgwbc
B4m4zT7Yg042KIDYUE82e893hY
A2m4zT7Yg042KIDYUE82e893hY

请注意,输出的顺序与原始文件中出现的顺序不同。

另一个选择是引入ripgreprg,这是grep的快速多功能版本。您可能需要使用sudo apt install ripgrep或其他包处理工具安装ripgrep。ripgrep的一个优点是它支持-r(replace)选项,您可以在该选项中使用反向引用:

rg -N -Po "(1(.{3}).+)k([AB].*)[\013 ]\2" -r '$1 $3' file

-r'$1$3'选项打印第一个和第三个捕获组,结果与perl相同。

 类似资料:
  • 我有非常大的二进制文件,其中包含y传感器的x个int16数据点,以及包含一些基本信息的头文件。二进制文件被写为每个采样时间的y值,最多x个采样,然后是另一组读数,依此类推。如果我想要所有的数据,我使用的是numpy。fromfile(),它工作得又快又好。然而,如果我只需要传感器数据的子集或特定传感器,我目前有一个可怕的double for循环,使用的是这要花很长时间。在python中有没有其他更

  • 我创建了一个方法,根据文件中的行号从文件中读取特定行。它对大多数文件都很好,但当我试图读取一个包含大量非常长的行的文件时,它需要很长时间,特别是当它在文件中的位置越来越深时。我还做了一些调试,似乎也占用了大量内存,但我不确定这是否可以改进。我知道还有一些其他的问题集中在如何从文件中读取某些行,但这个问题主要集中在性能方面。 如何优化此方法以使其比光速更快?

  • 问题内容: 我想读Python中的大文件时,了解在这个方法内存使用率的差异。 第1版,发现这里的计算器: 版本2,我用在此之前,我发现上面的代码: 该文件在两个版本部分阅读。而目前的一块可以被处理。在第二个例子,是在每个周期中获得新的内容,所以我认为这将做的工作,以 不 完整的文件加载到内存..? 但我真的不明白是什么呢,我敢肯定我得到的东西错在这里。任何人都可以解释给我吗? 还有别的,我感到困惑

  • 我有一个字符串。我想从中提取。为此,我正在努力 但是在输出上我得到了。 我怎样才能走出地狱世界。 谢谢

  • 根据https://docs.python.org/3.4/library/venv.html#module-venv所说的“每个虚拟环境都有自己的Python二进制文件(允许创建具有各种Python版本的环境)”,那么我如何使用具有Python 2.7二进制文件的venv模块来创建虚拟环境呢?

  • 下面是一个示例字符串: