Answers:
如果NUL
文件中任何地方都有字符,则grep会将其视为二进制文件。
可能有这样的解决方法cat file | tr -d '\000' | yourgrep
,首先消除所有null,然后搜索文件。
-a
/ --text
。
NUL
(可能是因为它调用了C的printf并给了它匹配的行?)。在这样的系统上,a grep cmd .sh_history
将返回与匹配“ cmd”的行一样多的空行,因为sh_history的每一行都有特定的格式,每行的开头都有a NUL
。(但您的评论“至少在GNU grep上可能是对的。我现在没有人可以测试,但我希望他们能很好地处理此问题)”
grep
在cygwin上视为二进制的文件,因为它的破折号(0x96)较长,而不是常规的ASCII连字符/减号(0x2d)。我猜这个答案解决了OP的问题,但看来它是不完整的。
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点的第一个字节:UTF-8-说明| en.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,因为该进程进入睡眠状态,而第二行不检查文件是否为二进制文件。
实时文件系统
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
快速grepping encoding_error_output
显示,唯一可以修改它的代码路径通过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是唯一的方法。
(printf '\n\0y') | grep y
用(printf '\n'; sleep 1; printf '\0y') | grep y
的实例。
export LC_CTYPE='en_US.UTF-8'
像我的示例中所说的还是其他意思?Buf阅读:令人惊叹的示例,已添加答案。您显然比我更阅读源代码,让我想起了那些“学生被开悟”的黑客ko吟:-)
我的一个文本文件突然被grep视为二进制文件:
$ file foo.txt
foo.txt: ISO-8859 text
解决方法是使用iconv
以下命令将其转换:
iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt
0xFC
十六进制,因此grep期望的范围超出utf8(最高0x7F
)。检查printf'a \ x7F'| 如Ciro所描述的grep'a'。
文件/etc/magic
或/usr/share/misc/magic
具有命令file
用于确定文件类型的序列列表。
请注意,二进制文件可能只是后备解决方案。有时,具有奇怪编码的文件也被视为二进制文件。
grep
在Linux上,有一些选项可以处理二进制文件,例如--binary-files
或-U / --binary
mbrlen()
。示例和源代码解释在:unix.stackexchange.com/a/276028/32558
我的一个学生有这个问题。有一个错误在grep
在Cygwin
。如果文件中有非ASCII字符,grep
并egrep
把它作为二进制。
--null-data
如果NUL
是定界符,则可能有用。