查找包含非打印字符(空字节)的文件

Mat*_*teo 6 unix linux bash grep

我的应用程序日志中包含一个包含奇怪字符的字段。仅当我使用命令时我才能看到这些字符less

我尝试将代码行的结果复制到文本文件中,我看到的是

CTP_OUT=^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
Run Code Online (Sandbox Code Playgroud)

我想知道是否有办法找到这些空字符。我尝试过使用grep命令,但没有显示任何内容

kva*_*our 9

我简直不敢相信,我可能会写一个涉及的答案cat

您观察到的字符是不可打印的字符,通常以Carret 表示法编写。字符的插入符号是一种可视化不可打印字符的方法。正如OP中提到的,^@是 的表示NULL

如果您的文件包含不可打印的字符,您可以使用以下命令将它们可视化cat -vET

-E, --show-ends:$在每行末尾 显示
-T, --show-tabs:TAB将字符 显示为^I
-v, --show-nonprinting:使用^M-表示法,除了LFDand之外TAB

来源:man cat

我已向其中添加了-E和标志,以将所有内容转换为不可打印的内容。-T

由于grep不会以任何形式输出不可打印字符本身,因此您必须通过管道输出才能cat看到它们。以下示例显示包含不可打印字符的所有行

显示所有包含不可打印字符的行:

$ grep -E '[^[:print:]]' --color=never file | cat -vET
Run Code Online (Sandbox Code Playgroud)

此处,ERE[^[:print:]]选择所有不可打印的字符。

显示所有带有以下内容的行NULL

$ grep -Pa '\x00' --color=never file | cat -vET
Run Code Online (Sandbox Code Playgroud)

请注意,我们需要在这里使用 Perl 正则表达式,因为它们理解十六进制和八进制表示法。

各种控制字符可以用C语言风格编写:\n匹配换行符、\t制表符、\r回车符、\f换页符等。

更一般地,\nnn,其中nnn是三个八进制数字的字符串,匹配本机代码点为 的字符nnn。如果您没有正好三位数,您很容易遇到麻烦。因此始终使用三个,或者从 Perl 5.14 开始,您可以用来\o{...}指定任意数量的八进制数字。

类似地,\xnn,其中nn是十六进制数字,匹配其本机序数为 的字符nn。同样,不完全使用两位数字会导致灾难,但您可以用来\x{...}指定任意数量的十六进制数字。

来源:Perl 5 版本 26.1 文档

一个例子:

$ printf 'foo\012\011\011bar\014\010\012foobar\012\011\000\013\000car\012\011\011\011\012' > test.txt
$ cat test.txt
foo
                bar

foobar

        car
Run Code Online (Sandbox Code Playgroud)

如果我们现在grep单独使用,我们会得到以下结果:

$ grep -Pa '\x00' --color=never test.txt

        car
Run Code Online (Sandbox Code Playgroud)

但通过管道将其传递给cat我们可以可视化控制字符:

$ grep -Pa '\x00' --color=never test.txt | cat -vET
^I^@^K^@car$
Run Code Online (Sandbox Code Playgroud)

原因--color=never如果你的 grep 被调整为有--color=auto--color=always它会添加额外的控制字符来解释为终端的颜色。这可能会让您对内容感到困惑。

$ grep -Pa '\x00' --color=always test.txt | cat -vET
^I^[[01;31m^[[K^@^[[m^[[K^K^[[01;31m^[[K^@^[[m^[[Kcar$
Run Code Online (Sandbox Code Playgroud)


Pau*_*ges 7

sed能。

 sed -n '/\x0/ { s/\x0/<NUL>/g; p}' file
Run Code Online (Sandbox Code Playgroud)

-n除非明确要求,否则跳过打印任何输出。
/\x0/仅选择具有空字节的行。封装多个命令,以便始终且仅当检测到线路上为空时才
{...}集体应用它们。用新的可见值替换空字节。你可以随心所欲地做它——我用的东西既相当明显,又不太可能发生。您可能应该先 grep 文件以确保在使用它之前该模式不存在。导致显示已编辑的行(因为它们有空字节)。/\x0/
s/\x0/<NUL>/g;<NUL>
p;

这基本上对空值sed有效grep