为什么我的“grep”停止过滤它认为是“二进制”的非 ASCII 文件?

Dom*_*que 15 linux grep textfiles binary-files windows-subsystem-for-linux

我正在使用 Windows-10 计算机,使用 WSL。

NLog我正在调查由C# 应用程序生成的日志文件。我期望日志条目出现在整个文件的各处,但我看到以下内容:

Linux prompt> grep "geen mengcontainer" logfile.log
2023-03-07 07:25:08.7971 | Warn | ... | geen mengcontainer.
2023-03-07 07:25:09.8285 | Warn | ... | geen mengcontainer.
2023-03-07 07:25:10.8754 | Warn | ... | geen mengcontainer.
Binary file logfile.log matches
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,在 07:25:10 之后,grep即使文件在当天剩余的时间里继续前进,也会停止。似乎有一些字符告诉grep该文件不是文本文件,而是二进制文件,导致grep停止工作。

有关该文件的更多信息:

Linux prompt>file logfile.log
logfile.log: ASCII text, with CRLF line terminators
Run Code Online (Sandbox Code Playgroud)

有关我的 Linux WSL 安装的更多信息:

Linux prompt>uname -a
Linux ComputerName 4.4.0-19041-Microsoft
  #2311-Microsoft Tue Nov 08 17:09:00 PST 2022 
  x86_64 x86_64 x86_64 GNU/Linux

Linux prompt> cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
...
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
Run Code Online (Sandbox Code Playgroud)

有关我的安装的更多信息grep

Linux prompt> grep --version
grep (GNU grep) 3.4
Run Code Online (Sandbox Code Playgroud)

我能做些什么?

  • 有谁知道如何查找和替换负责grep停止过滤的字符?
  • 有谁知道我可以添加哪些额外参数或开关grep以避免停止过滤?
  • 有谁知道一个grep不具有这样行为的版本?(请考虑到这些apt update东西在我的环境中不起作用)

提前致谢

use*_*686 33

用于grep -a强制文件始终被视为文本。

\n

“二进制文件”检测是代码页敏感的 \xe2\x80\x93 如果 grep 在 Linux 上像往常一样期望 UTF-8 输入,它实际上最终会检测到“ANSI”(Windows-125x,ISO 8859-x)编码的文本文件作为二进制文件。在“C”语言环境下使用LC_CTYPE=C grep或运行 grepLC_ALL=C grep也可以避免此问题。

\n

(此外,“file”所说的输入为“ASCII”完全基于对文件中初始字节的快速查看;它实际上并不扫描整个内容,而“grep”当然会扫描整个内容。)

\n

通常整个文件采用相同的编码(即所有文件都可能是非 UTF-8),因此查找有问题的字符的一个简单方法是搜索非 ASCII 字节(LC_ALL=C 可能需要):

\n
grep -a -P -n --color '[^\\x00-\\x7F]' logfile.log\n
Run Code Online (Sandbox Code Playgroud)\n
perl -ne 'print "Line $.:\\t$_" if /[^\\0-\\177]/' < logfile.log\n
Run Code Online (Sandbox Code Playgroud)\n

这也会突出显示有问题的字节:

\n
perl -ne 'print "Line $.:\\t$_" if s/[^\\0-\\177]/sprintf"\\e[41m<%02X>\\e[m",ord$&/ge' < logfile.log\n
Run Code Online (Sandbox Code Playgroud)\n

如果文件有效的 UTF-8(除了一些奇数行之外),请使用类似的方法来打印 UTF-8 解码失败的行:

\n
perl -MEncode -ne 'print "Line $.:\\t$_" if !eval{decode("UTF-8", $_, Encode::FB_CROAK)}' < logfile.log\n
Run Code Online (Sandbox Code Playgroud)\n

  • NUL 字节也可能使它检测到二进制文件,即使在 C 语言环境中,例如 `printf 'xyz\0' |LC_ALL=C grep xyz` 至少与我拥有的 grep 给出“二进制文件(标准输入)匹配”。 (3认同)
  • 非常感谢您的快速回复:使用“grep -a”我确实可以让“grep”进行完整的过滤。分析完成后,我将查看您提到的“Perl”命令,以找出我的文件可能出现的问题。 (2认同)
  • @Dominique当你(不小心)grep实际的二进制文件时,这可能会咬你。生成的二进制输出可能会扰乱您的终端并产生意想不到的副作用。这是 grep 默认情况下如此行为的一个重要原因。我怀疑这也可能是人们拒绝你的编辑的原因。 (2认同)
  • _改变我的“grep”以使其始终将文件视为文本文件_是一个糟糕的主意。这意味着,如果您不小心“grep a CHROME.EXE”,您将收到大量兆字节的二进制噪音,这是 Chrome 二进制文件中碰巧具有值 0x61(小写“a”)的每个字节的一个块。如果您有包含二进制数据的文本文件,它们应该是稀有的(IOW,默认情况下是斑马),并且您最好弄清楚为什么二进制数据会悄悄进入日志(它始终是日志),然后修复所有内容进行日志记录,这样就不会再发生了。 (2认同)