binary file foo.txt matches
。我注意到文件中包含一些ascii
NUL
字符,我相信这是数据库转储中的工件。那么,是什么让grep认为这些文件是二进制文件?
NUL
的字符?文件系统上是否有标志?要使grep向我显示行匹配项,我需要更改什么?#1 楼
如果文件中的任何位置都有NUL
字符,则grep会将其视为二进制文件。可能存在类似
cat file | tr -d 'q4312079q0' | yourgrep
这样的变通办法,首先消除所有空值,然后搜索文件。评论
...或至少在GNU grep中使用-a /-text。
–德罗伯特
2012年11月26日20:44
@derobert:实际上,在某些(较旧的)系统上,grep看到了行,但是它的输出会在第一个NUL处截断每个匹配的行(可能是因为它调用了C的printf并给了它匹配的行?)。在这样的系统上,grep cmd .sh_history将返回与匹配“ cmd”的行一样多的空行,因为sh_history的每一行都有特定的格式,每行的开头都有NUL。 (但是您的评论“至少在GNU grep上可能是对的。我现在没有人可以测试,但我希望他们能很好地处理此问题)”
–奥利维尔·杜拉克(Olivier Dulac)
13年11月25日在11:46
是否存在NUL字符是唯一标准?我对此表示怀疑。它可能比这更聪明。任何超出Ascii 32-126范围的东西都是我的猜测,但是我们必须查看源代码才能确定。
–迈克尔·马丁内斯(Michael Martinez)
15年8月14日在16:58
我的信息来自特定grep实例的手册页。您对实施的评论是有效的,来源优于docs。
–bbaja42
15年8月18日在22:31
我有一个文件,其在cygwin上的grep被认为是二进制文件,因为它的长破折号(0x96)而不是常规的ASCII连字符/减号(0x2d)。我猜这个答案解决了OP的问题,但看来它是不完整的。
–cp.engr
16年2月15日在16:15
#2 楼
grep -a
为我工作:$ grep --help
[...]
-a, --text equivalent to --binary-files=text
评论
这是IMO最好,最便宜的答案。
–pydsigner
16-09-24在18:32
但不符合POSIX
–马特奥
19年8月9日在8:08
您介意解释为什么不是吗?对于我们谁都可以将此答案作为选择的所有人来说,最好弄清楚一点。谢谢 :)。
– ivanleoncz
19年11月4日在19:36
嘿,我来这里是第二次重新学习这个LOL。文本中的法语口音(变音符号)使grep变成了barf
– zzapper
20-10-26在9:43
#3 楼
您可以使用strings
实用程序从任何文件中提取文本内容,然后通过grep
将其通过管道传输,如下所示:strings file | grep pattern
。评论
grep处理可能部分损坏的日志文件的理想选择
–汉斯·R。
2015年2月27日在7:43
是的,有时还会发生二进制混合日志记录。很好
–sdkks
17年3月3日在16:59
#4 楼
GNU grep 2.24 RTFS结论:仅2种和2种情况:
NUL
,例如根据C99 printf 'ambrlen()
' | grep 'a'
的编码错误,例如: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,因为该进程进入了睡眠状态,第二行读取了不检查文件是否为二进制文件。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;
因此,当找到空值时,
0 <= nlines_first_null
变为true。 TODO
nlines_first_null < nlines
何时会为假?我很懒POSIX
未定义二进制选项grep-在文件中搜索模式| pubs.opengroup.org和GNU grep没有记录它,因此RTFS是唯一的方法。
评论
令人印象深刻的说明!
–user394
16年4月13日在2:02
请注意,仅在UTF-8语言环境中检查有效的UTF-8。还要注意,检查仅在从文件读取的第一个缓冲区上进行,对于我的系统,该文件对于常规文件似乎是32768字节,但对于管道或套接字,则可以小到一个字节。比较(printf'\ n \ 0y')| grep y与(printf'\ n'; sleep 1; printf'\ 0y')|例如grep y。
–StéphaneChazelas
16-4-13在12:18
@StéphaneChazelas“请注意,仅在UTF-8语言环境中才检查有效的UTF-8”:您的意思是关于导出LC_CTYPE ='en_US.UTF-8'的示例,还是其他的? Buf阅读:令人惊叹的示例,添加到答案中。您显然比我更多地阅读了源,让我想起了那些“学生开悟”的黑客koans :-)
– Ciro Santilli郝海东冠状病六四事件法轮功
16年4月13日在13:05
我也没有研究细节,但是最近
–StéphaneChazelas
16年4月13日在13:09
@CiroSantilli巴拿马文件六四事件法轮功您测试了哪个版本的GNU grep?
– jrw32982
16年6月8日在23:33
#5 楼
我的一个文本文件突然被grep视为二进制文件:$ file foo.txt
foo.txt: ISO-8859 text
解决方案是使用
iconv
将其转换:iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt
评论
这也发生在我身上。特别是,原因是ISO-8859-1编码的不间断空格,为了使grep在文件中进行搜索,我必须将其替换为常规空格。
– Gallaecio
2015年6月9日13:50
grep 2.21将ISO-8859文本文件视为二进制文件,请在grep命令之前添加export LC_ALL = C。
– netawater
2015年8月17日在2:52
@netawater谢谢!这是例如如果文本文件中包含类似Müller的内容,则会出现这种情况。这是十六进制的0xFC,因此超出grep预期的范围是utf8(最高0x7F)。检查printf'a \ x7F'|如Ciro所描述的grep'a'。
–Anne van Rossum
16年11月26日在16:51
#6 楼
文件/etc/magic
或/usr/share/misc/magic
具有命令file
用于确定文件类型的序列列表。 请注意,二进制可能只是一个备用解决方案。有时,具有奇怪编码的文件也被视为二进制文件。
Linux上的
grep
有一些选项可以处理二进制文件,例如--binary-files
或-U / --binary
评论
更准确地说,根据C99的mbrlen()编码错误。示例和源代码解释位于:unix.stackexchange.com/a/276028/32558
– Ciro Santilli郝海东冠状病六四事件法轮功
16年4月12日在20:51
#7 楼
我的一个学生有这个问题。grep
中的Cygwin
中存在错误。如果文件包含非Ascii字符,则grep
和egrep
会将其视为二进制文件。 评论
这听起来像一个功能,而不是一个错误。特别是考虑到有命令行选项来控制它(-a / --text)
–威尔·谢泼德(Will Sheppard)
18年1月29日,11:39
#8 楼
实际回答“是什么使grep认为文件是二进制文件?”的问题,您可以使用iconv
:$ iconv < myfile.java
iconv: (stdin):267:70: cannot convert
在我的情况下,西班牙语字符显示正确在文本编辑器中,但grep认为它们是二进制的;
iconv
输出将我指向这些字符的行号和列号对于
NUL
字符,iconv
会认为它们是正常的,并且不会打印此类输出,因此该方法不适合#9 楼
我有同样的问题。我用vi -b [filename]
查看添加的字符。我找到了控制字符^@
和^M
。然后在vi中键入:1,$s/^@//g
删除^@
字符。对^M
重复此命令。 警告:要获取“蓝色”控制字符,请按Ctrl + v,然后按Ctrl + M或Ctrl + @。然后保存并退出vi。
#10 楼
我也遇到了这个问题,但就我而言,这是当匹配的行太长时引起的。file myfile.txt
myfile.txt: UTF-8 Unicode text, with very long lines
grep
可以在整个文件中运行很多模式,但是当模式匹配“很长的行”时“它以Binary file myfile.txt matches
停止。添加
-a
也可以解决此问题,但预先为文件准备NULL或其他无效字符将没有任何效果(没有其他方式的grep无法完成)。在这种情况下,冒犯的行有25k +个字符!我不明白的是为什么它仅在
grep
试图返回该行而不是在处理其他模式时才发生。
评论
如果NUL是分隔符,则--null-data可能很有用。