我的机器上有一些来自 Windows 系统的数据库转储。它们是文本文件。我正在使用 cygwin 来查看它们。这些似乎是纯文本文件;我用记事本和写字板等文本编辑器打开它们,它们看起来很清晰。但是,当我对它们运行 grep 时,它会说binary file foo.txt matches.
我注意到这些文件包含一些 asciiNUL字符,我认为它们是数据库转储中的工件。
那么是什么让 grep 认为这些文件是二进制的呢?的NUL性格吗?文件系统上有标志吗?我需要更改什么才能让 grep 显示匹配行?
bba*_*a42 162
如果NUL文件中的任何位置都有字符,grep 会将其视为二进制文件。
可能有这样的解决方法cat file | tr -d '\000' | yourgrep来首先消除所有空值,然后搜索文件。
小智 156
grep -a 为我工作:
$ grep --help
[...]
-a, --text equivalent to --binary-files=text
Run Code Online (Sandbox Code Playgroud)
小智 25
您可以使用strings实用工具从任何文件,然后把它管道的文本内容grep,就像这样:strings file | grep pattern。
Cir*_*郝海东 21
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'
Run Code Online (Sandbox Code Playgroud)
因为\x80不能是 UTF-8 Unicode 点的第一个字节:UTF-8 - 描述 | 维基百科
这些检查仅在输入的第 N 个字节之前完成,其中 N = TODO(在一个测试系统中为 32KiB)。如果在第 N 个字节后检查失败,则该文件仍被视为文本文件。(由 Stéphane Chazelas 提及)。
最多只能读取第一个缓冲区
因此,如果在一个非常大的文件中间发生 NUL 或编码错误,无论如何它都可能会被 grepped。
我想这是出于性能原因。
例如:这会打印以下行:
printf '%10000000s\n\x80a' | grep 'a'
Run Code Online (Sandbox Code Playgroud)
但这不会:
printf '%10s\n\x80a' | grep 'a'
Run Code Online (Sandbox Code Playgroud)
实际缓冲区大小取决于读取文件的方式。例如比较:
export LC_CTYPE='en_US.UTF-8'
(printf '\n\x80a') | grep 'a'
(printf '\n'; sleep 1; printf '\x80a') | grep 'a'
Run Code Online (Sandbox Code Playgroud)
使用sleep,第一行即使只有 1 个字节长也会传递给 grep,因为进程进入睡眠状态,并且第二次读取不会检查文件是否为二进制文件。
实时文件系统
git clone git://git.savannah.gnu.org/grep.git
cd grep
git checkout v2.24
Run Code Online (Sandbox Code Playgroud)
查找 stderr 错误消息的编码位置:
git grep 'Binary file'
Run Code Online (Sandbox Code Playgroud)
引导我们/src/grep.c:
if (!out_quiet && (encoding_error_output
|| (0 <= nlines_first_null && nlines_first_null < nlines)))
{
printf (_("Binary file %s matches\n"), filename);
Run Code Online (Sandbox Code Playgroud)
如果这些变量命名得很好,我们基本上就得出了结论。
编码错误输出
快速搜索encoding_error_output显示可以修改它的唯一代码路径通过buf_has_encoding_errors:
clen = mbrlen (p, buf + size - p, &mbs);
if ((size_t) -2 <= clen)
return true;
Run Code Online (Sandbox Code Playgroud)
然后只是man mbrlen。
nlines_first_null 和 nlines
初始化为:
intmax_t nlines_first_null = -1;
nlines = 0;
Run Code Online (Sandbox Code Playgroud)
所以当发现空值时0 <= nlines_first_null变为真。
TODO 什么时候可以nlines_first_null < nlines是假的?我变懒了。
POSIX
不定义二元选项grep - 在文件中搜索模式 | pubs.opengroup.org和 GNU grep 没有记录它,所以 RTFS 是唯一的方法。
我的一个文本文件突然被 grep 视为二进制文件:
$ file foo.txt
foo.txt: ISO-8859 text
Run Code Online (Sandbox Code Playgroud)
解决方案是使用iconv以下方法转换它:
iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt
Run Code Online (Sandbox Code Playgroud)
小智 5
该文件/etc/magic或/usr/share/misc/magic具有命令file用于确定文件类型的序列列表。
请注意,二进制可能只是一种后备解决方案。有时具有奇怪编码的文件也被视为二进制文件。
grep在 Linux 上有一些选项来处理二进制文件,如--binary-files或-U / --binary
| 归档时间: |
|
| 查看次数: |
164718 次 |
| 最近记录: |