如何在文本文件中找到二进制数据?

如何在文本文件中找到二进制数据?

我有一个巨大的日志文件(几 GB),但不知何故其中有二进制数据(grep 对此感到烦恼),这当然不应该。

无论如何,我知道如何读取该文件。

我不知道如何才能找到其中的错误二进制数据,所以我是否可以通过查看周围的文本来确定它被记录在哪里?

答案1

我刚刚遇到了完全相同的问题(尽管它只是一个几兆字节的日志文件)。与许多问题一样,它只需要几个命令就可以解决。

cmp /path/to/file.log <(strings /path/to/file.log)

cmp比较文件并告诉你在哪里它们有所不同(不同于 diff,它告诉你如何它们不同)。strings从二进制文件返回有效的文本字符串。<(…)让您将一个命令的输出作为另一个命令的文件描述符。

基本上,您将日志文件与日志文件中的文本字符串进行比较,以便找到它们首先不同的地方。

例如,我得到A and B differ: byte 1450315, line 6390。运行tail -n +6390 /path/to/file.log | less显示从“坏”行开始的日志,或者您可以通过管道| hexdump -C | less查看十六进制(管道head -n 1对我来说不起作用,因为二进制是\x00字符,只有在有寻呼机时才显示)

(注意:如果机器没有足够的内存,这可能无法很好地处理多 GB 的日志 - 我不知道内存效率strings如何cmp

答案2

我已经解决了同样的问题。对我有用的方法是head逐步简单地查看文件,然后 grep 以查看二进制字符出现在哪一行。

一开始,我调用head -n 1,没有二进制字符。然后head -n 2,然后head -n 3...... 等等。很快我就找到了二进制字符所在的行。

答案3

基于@ibboard 的伟大想法find-non-printable.sh::

#!/bin/sh
usage="$0 FILE - Locates first non-printable byte, as in 'FILE - differ: byte 21881, line 507'";
n_bytes=$(stat --printf='%s' "$1");
# -w: --include-all-whitespace
strings -w "$1" | cmp -n "$n_bytes" "$1";
  • 当没有发现不可打印字符时不输出任何内容,而不是像 这样的消息cmp: EOF on FILE after byte 1677, line 47
  • 使用简单管道代替<()。与 POSIX shell 配合使用,而不需要 Bash 或 ZSH。输出显示-为文件名而不是/dev/...
  • 当文件包含空行时,按预期工作。这需要strings支持 的实现-w,例如 GNU strings。如果没有这个,结果只会指向第一个空行,这通常不是所需的结果。
  • 用户只需输入一次文件名。

答案4

如果有my_file包含(在vim):

test data 1
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@test data 2
test data 3

grep受到空字节(十六进制值 00,表示为^@)的困扰vim。如果您使用 搜索常规字符串“数据”,$ grep 'data' my_file您将得到Binary file my_file matches不是预期的结果。如果您想手动检查/删除空字节,您可以使用以下方法找到有问题的字节:

$ < my_file hexdump -C | grep -C2 ' 00'
00000000  74 65 73 74 20 64 61 74  61 20 31 0a 00 00 00 00  |test data 1.....|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 74 65  |..............te|
00000020  73 74 20 64 61 74 61 20  32 0a 74 65 73 74 20 64  |st data 2.test d|
00000030  61 74 61 20 33 0a                                 |ata 3.|

并查看空字节附近的常规字符串,然后您可以在 vim 中搜索并编辑(不要搜索句点;它们代表空格字符,如换行符和空字节,而不是文字.。)如果您想删除它们以编程方式

$ < my_file sed 's/\x0//g' > my_file_without_nulls

相关内容