使用grep排除二进制文件
1. 概述
我们使用grep命令过滤文件中特定字符模式的 搜索。文本搜索模式称为正则表达式。它是最常用的 Linux 命令之一,用于显示包含我们试图搜索的模式的行。
当我们使用grep工具时,我们可能希望避免扫描二进制文件以节省时间。这有时可能与某些文本文件以及实际的真实二进制文件有关。
在这个简短的教程中,我们将了解如何使用grep以及如何从搜索中排除二进制文件。
2. 为什么二进制文件会成为grep的问题
有两种情况grep可能认为我们的文件是二进制文件;编码错误和 NUL 字节。让我们进一步探索它们。
2.1. 编码错误
如果文件包含根据 C99 mbrlen函数的编码错误,则grep工具将文件视为二进制文件。我们可以通过一个例子看到这一点。让我们创建一个带有 UTF-8 编码错误的文件,因为*\x80*不能是 UTF-8 Unicode 点的第一个字节:
$ printf 'Encoding\x80' >> encoding.txt
如果我们现在用grep搜索匹配的单词*“Encoding”*:
$ grep "Encoding" encoding.txt
Binary file encoding.txt matches
我们看到,当文件encoding.txt只是一个有编码错误的文本文件时, grep将它解释为二进制文件。
2.2. NUL 字节
grep工具将扫描缓冲区以尝试读取 NUL 字节,但它也会尝试查看是否可以确定文件的剩余数据中必须包含 NUL。空洞是未写入的数据,Unix 要求它们读取为 NUL 字节,因此如果文件包含空洞,则它包含 NUL,并且grep会将我们的文件视为二进制文件。让我们看一个非常简单的示例,其中文本文件包含 NUL 字节:
$ printf "File with NUL byte\0" >> nul.txt
现在让我们在这个文件中使用grep命令:
$ grep "NUL" nul.txt
Binary file nul.txt matches
我们可以看到,同样在这种情况下,grep认为这是一个二进制文件,而不仅仅是一个带有 NUL 字节的纯文本文件。
3. 带有二进制文件的grep命令
当我们尝试查找包含某个字符串值的所有文件时,检查我们可能不想检查的二进制文件可能会非常昂贵。在某些情况下,二进制文件可能非常大,我们会浪费时间和资源扫描它们。让我们看一个我们不想查看二进制文件内部的示例。
3.1. 在不抑制二进制文件的情况下使用grep
假设我们要在所有文件中搜索文本*“printHello”* 。这个词对应于定义的 C 函数*“void printHello”*,并在我们的项目中多次使用,但是,我们想知道在哪里以及如何使用。我们现在可以生成文本文件(hello.c):
$ cat <<EOF >>hello.c
#include <stdio.h>
#include <stdlib.h>
void printHello(){printf ("Hello World\n");}
int main() {
printHello();
return 0;
}
EOF
现在让我们编译hello.c并生成二进制文件 ( out.x ):
$ gcc hello.c -o out.x
为了生成out.x文件,我们使用 GCC,大多数 Linux 发行版上都存在 C 编译器。所以,现在让我们在所有文件中使用grep “printHello”:
$ grep "printHello"
hello.c:void printHello(){printf ("Hello World\n");}
hello.c:printHello();
Binary file out.x matches
grep输出表明在hello.c文件中找到了*“printHello” 。*但是,它也可以在二进制文件中找到。
3.2. 使用grep抑制二进制文件
我们希望只看到包含代码的文本文件,所以现在让我们使用grep跳过二进制文件:
$ grep -I "printHello" *
hello.c:void printHello(){printf ("Hello World\n");}
hello.c:printHello();
这里我们使用了*-I参数,也可以使用-binary-files=without-match*。这些是跳过二进制文件的grep选项。这正是我们所寻找的。我们现在有来自文本文件的所有匹配项,但不是来自二进制文件。