it-swarm.cn

是什么使grep认为文件是二进制文件?

我的盒子上有一些Windows系统上的数据库转储。它们是文本文件。我正在使用cygwin通过它们进行grep。这些似乎是纯文本文件;我使用记事本和写字板等文本编辑器打开它们,它们看起来清晰易读。但是,当我在它们上运行grep时,它会说binary file foo.txt matches

我注意到文件中包含一些ASCII NUL字符,我相信这是数据库转储中的工件。

那么,什么使grep认为这些文件是二进制文件? NUL字符?文件系统上是否有标志?我需要更改什么才能让grep向我显示行匹配项?

203
user394

如果文件中的任何位置都有NUL字符,则grep会将其视为二进制文件。

可能有这样的解决方法cat file | tr -d '\000' | yourgrep首先消除所有null,然后搜索文件。

139
bbaja42

grep -a为我工作:

$ grep --help
[...]
 -a, --text                equivalent to --binary-files=text
140
Plouff

您可以使用strings实用程序从任何文件中提取文本内容,然后将其通过grep传递给管道,如下所示:strings file | grep pattern

21
holgero

GNU grep 2.24 RTFS

结论:仅2例和2例:

  • NUL,例如_printf 'a\0' | grep 'a'_

  • 根据C99 mbrlen()的编码错误,例如:

    _export LC_CTYPE='en_US.UTF-8'
    printf 'a\x80' | grep 'a'
    _

    因为_\x80_不能是UTF-8 Unicode点的第一个字节: TF-8-描述| zh.wikipedia.org

此外,正如StéphaneChazelas所提到的 是什么使grep认为文件是二进制的?| Unix&Linux Stack Exchange ,这些检查仅进行到读取长度为TODO的第一个缓冲区为止。

仅读取第一个缓冲区

因此,如果在非常大的文件中间发生NUL或编码错误,则无论如何都会将其grep掉。

我想这是出于性能原因。

例如:这将打印以下行:

_printf '%10000000s\n\x80a' | grep 'a'
_

但这不是:

_printf '%10s\n\x80a' | grep 'a'
_

实际的缓冲区大小取决于文件的读取方式。例如。相比:

_export LC_CTYPE='en_US.UTF-8'
(printf '\n\x80a') | grep 'a'
(printf '\n'; sleep 1; printf '\x80a') | grep 'a'
_

使用sleep,即使只有1个字节长,第一行也会传递给grep,因为该进程进入睡眠状态,而第二行则不检查文件是否为二进制。

[〜#〜] rtfs [〜#〜]

_git clone git://git.savannah.gnu.org/grep.git 
cd grep
git checkout v2.24
_

查找stderr错误消息的编码位置:

_git grep 'Binary file'
_

导致我们到达_/src/grep.c_:

_if (!out_quiet && (encoding_error_output
                    || (0 <= nlines_first_null && nlines_first_null < nlines)))
    {
    printf (_("Binary file %s matches\n"), filename);
_

如果这些变量都得名,我们就可以得出结论。

encoding_error_output

_encoding_error_output_的快速grepping显示,唯一可以修改它的代码路径通过_buf_has_encoding_errors_:

_clen = mbrlen (p, buf + size - p, &mbs);
if ((size_t) -2 <= clen)
  return true;
_

然后只需_man mbrlen_。

nlines_first_null和nlines

初始化为:

_intmax_t nlines_first_null = -1;
nlines = 0;
_

因此,当找到null时,_0 <= nlines_first_null_变为true。

TODO _nlines_first_null < nlines_何时会为假?我很懒.

[〜#〜] posix [〜#〜]

不定义二进制选项 grep-在文件中搜索模式| pubs.opengroup.org ,并且GNU grep没有记录它,因此RTFS是唯一方法。

我的一个文本文件突然被grep视为二进制文件:

$ file foo.txt
foo.txt: ISO-8859 text

解决方案是使用iconv进行转换:

iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt
6
zzapper

文件 /etc/magic 要么 /usr/share/misc/magic具有命令file用于确定文件类型的序列列表。

注意二进制可能只是一个备用解决方案。有时,具有奇怪编码的文件也被视为二进制文件。

Linux上的grep具有一些处理二进制文件的选项,例如--binary-files 要么 -U / --binary

5
klapaucius

实际回答“什么使grep认为文件是二进制文件?”的问题,您可以使用iconv

$ iconv < myfile.Java
iconv: (stdin):267:70: cannot convert

以我为例,在文本编辑器中正确显示了西班牙语字符,但是grep认为它们是二进制的。 iconv的输出将我指向这些字符的行号和列号

NUL个字符的情况下,iconv会认为它们是正常的,并且不会打印这种输出,因此此方法不适合

2
golimar

我的一个学生有这个问题。 grep中的Cygwin中存在错误。如果文件包含非Ascii字符,则grepegrep将其视为二进制文件。

2
Joan Pontius

我有同样的问题。我使用vi -b [filename]查看添加的字符。我找到了控制字符^@^M。然后在vi中键入:1,$s/^@//g以删除^@个字符。对^M重复此命令。

警告:要获取“蓝色”控制字符,请按 Ctrl+v 然后 Ctrl+M 要么 Ctrl+@。然后保存并退出vi。

1
Not Sure