我有一个巨大的日志文件(几 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
,例如 GNUstrings
。如果没有这个,结果只会指向第一个空行,这通常不是所需的结果。 - 用户只需输入一次文件名。
答案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