如何grep包含一些二进制数据的文本文件?


122

grep返回

二进制文件test.log匹配

例如

echo    "line1 re \x00\r\nline2\r\nline3 re\r\n" > test.log  # in zsh
echo -e "line1 re \x00\r\nline2\r\nline3 re\r\n" > test.log  # in bash
grep re test.log

我希望结果将显示line1和line3(总共两行)。

是否可以使用tr将无法打印的数据转换为可读数据,以使grep再次工作?


请注意,有一个程序可以从二进制文件中过滤出二进制字符,并且仅保留文本字符(可读)。此处: soft.tahionic.com/download-words_extractor/index.html
InTheNameOfScience,2013年

对不起,可是......你不是失踪-eecho命令?
Sopalajo de Arrierez 2014年

如果使用“ zsh”,没有-e也可以。如果使用“ bash”,则应添加“ -e”。
Daniel YC Lin

Answers:


67

您可以通过来运行数据文件cat -v,例如

$ cat -v tmp/test.log | grep re
line1 re ^@^M
line3 re^M

然后可以进一步进行后期处理以去除垃圾;这最类似于您关于tr用于任务的查询。


5
解决了我的问题。谢谢!这是man cat关于什么的内容-v-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
tommy.carstensen

请注意,这也适用于管道。例如set | cat -v | grep variable
funroll

1
如果grep --text有效,为什么要使用它?这似乎要复杂得多。
Michael Haefele'3

grep --text并不总是有效;它尊重CTRL + D作为文件终止符。因此,如果您的二进制文件中有该文件,则grep会提前退出。
汤米


91

一种方法是无论如何都将二进制文件简单地视为文本,grep --text但这很可能导致二进制信息被发送到您的终端。如果您正在运行一个解释输出流的终端(例如VT / DEC或许多其他终端),那并不是一个好主意。

或者,您可以tr使用以下命令发送文件:

tr '[\000-\011\013-\037\177-\377]' '.' <test.log | grep whatever

这会将小于空格字符(换行符除外)和大于126的所有内容更改为.字符,仅保留可打印内容。


如果您希望将每个“非法”字符替换为一个不同的字符,则可以使用以下C程序(一种经典的标准输入过滤器):

#include<stdio.h>
int main (void) {
    int ch;
    while ((ch = getchar()) != EOF) {
        if ((ch == '\n') || ((ch >= ' ') && (ch <= '~'))) {
            putchar (ch);
        } else {
            printf ("{{%02x}}", ch);
        }
    }
    return 0;
}

这将为您提供{{NN}}NN字符的十六进制代码在哪里。您可以简单地调整printf所需的任何输出样式进行。

您可以在此处看到该程序的运行情况:

pax$ printf 'Hello,\tBob\nGoodbye, Bob\n' | ./filterProg
Hello,{{09}}Bob
Goodbye, Bob

此方法将所有二进制char映射到相同的“。”中。符号。还有其他将它们映射到可读符号的方法吗?
Daniel YC Lin

当然,您可以通过其他筛选器程序来运行它,我在更新中提供了其中一个。
paxdiablo'4

1
我认为tr '[:cntrl:] '.'更好。它应该\000-\010\013\014\016-\037\177-\377'在您的tr语法中。
Daniel YC Lin

2
经过测试,tr '[\000-\010\013\014\016-\037\177-\377]' '_'可行,cntrl不适合我的情况。
Daniel YC Lin

2
您可以cat通过管道grep --text输入tr来保存步骤,反之亦然。这也使您可以grep多个文件,并在输出中保留文件名引用。
aaaantoine 2014年

33

您可以使用“字符串”从二进制文件中提取字符串,例如

strings binary.file | grep foo

对我来说效果很好,因为源是每行带有UID的调试日志。谢谢。
mbrownnyc

对我来说也很好 感谢您的回答。挽救了我的一天:)
Shekhar 2014年

2
我感谢@paxdiablo的回答,但是对于快速的回答和继续工作,您不能对此表示怀疑。
2014年

尝试使用paxdiablo解决方案,但是并没有给我任何我期望的结果。@moodywoody您的解决方案快速,简单,并且输出的正是我所需要的!
justinhartman 2014年

20

您可以使用以下命令强制grep查看二进制文件:

grep --binary-files=text

您可能还想添加-o--only-matching),以免浪费大量的二进制垃圾,这些垃圾会使您的终端机瘫痪。


可能会输出二进制垃圾,如果输出是终端并且终端驱动程序将其中一些解释为命令,则二进制垃圾可能会带来讨厌的副作用。
Daniel YC Lin

如果使用--only-matching,并且您的正则表达式不匹配任意二进制数据,则不会有问题。
AB

如果正则表达式为“ first。* end”,并且二进制数据包含在“。*”模式中,则无法为我的后期处理纠正过程。不管怎样,谢谢。
Daniel YC Lin

16

从Grep 2.21开始,二进制文件的处理方式有所不同

搜索二进制数据时,grep现在可以将非文本字节视为行终止符。这可以显着提高性能。

所以现在发生的是,对于二进制数据,所有非文本字节(包括换行符)都被视为行终止符。如果要更改此行为,可以:

  • 使用--text。这将确保只有换行符才是行终止符

  • 使用--null-data。这将确保只有空字节是行终止符




2

你可以做

strings test.log | grep -i

这会将give输出作为可读字符串转换为grep。


0

您也可以尝试使用Word Extractor工具。Word Extractor可以与计算机中的任何文件一起使用,以将包含人类文本/单词的字符串与二进制代码(exe应用程序,DLL)分开。


就我而言,我不需要单词提取器,我需要保留行号。
Daniel YC Lin

0

这是我在未安装“字符串”命令的系统中使用的命令

cat yourfilename | tr -cd "[:print:]"

一键打印即可打印文本并删除无法打印的字符,这与“ cat -v filename”不同,后者需要进行一些后处理才能删除不需要的内容。请注意,某些二进制数据可能是可打印的,因此您仍然会在这些好东西之间得到一些混乱。我认为如果您可以使用字符串,也可以消除这种混乱。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.