递归 grep 不列出某些文件的匹配项

递归 grep 不列出某些文件的匹配项

我使用 GNU grep 3.4 来查找包含特定模式的脚本。为此,我grep像这样递归调用

grep -rin . -e "pattern" 

模式只是一个单词,不是正则表达式。奇怪的是,输出没有列出某些文件中肯定包含该字符串的出现情况。

我尝试打开这些文件vim并使用进行搜索/pattern,它找到了模式。编码显示为vim[dos:utf-8:]当我复制该行并将其写入新文件时,上述grep命令会正确列出它。

为什么不grep列出原始文件?

答案1

Grep(或者至少是较旧的版本)不理解 UTF8。因此,组合字符、连字符点或其他不可见数据可能会阻止 grep。

Grep 也受到 $LC_ALL、$LC_CTYPE 和 $LANG 的值的影响。

使用 vim 保存 grep 无法找到的单词周围的几行,然后对该小示例文件进行十六进制转储。您可能会明白 grep 失败的原因

您也可以使用 vim 命令(gag8)来检查字符,但十六进制转储可能更清晰

答案2

我找到了问题(在另一个答案的帮助下)。文件“grep”没有显示任何输出,但实际上并未utf-8编码utf-16be。我使用 hexdump 了解到了这一点(感谢@RedGrittyBrick):

hd file_for_which_grep_works_as_expected.txt

产量

00000000  20 20 20 20 50 61 74 74  65 72 6e 0a              |    Pattern.|
0000000c

然而

hd file_for_which_grep_fails.txt

00000000  fe ff 00 50 00 61 00 74  00 74 00 65 00 72 00 6e  |...P.a.t.t.e.r.n|
00000010  00 0a                                             |..|
00000012

因此,使用以下方法仔细检查编码

file -i file_for_which_grep_fails.txt

将其标识为text/plain; charset=utf-16be

我没有意识到所utf-8展示的vim实际上是缓冲编码,而不是文件编码。执行:set fileencodingvim也正确显示fileencoding=utf-16(在此处找到https://superuser.com/a/28783/1210682)。

因此,问题在于我的代码grep无法处理utf-16编码文件。这里已经对此进行了描述:https://superuser.com/a/231471/1210682utf-16。但是,当我以递归方式使用将文件转换为utf-8之前的补救措施grep时,它不起作用,因为我事先不知道哪些文件可能是utf-8,哪些是,utf-16并且正在搜索大量文件。

有不同的解决方案,我将在这里简要介绍其中两种:

  1. A快速而粗略的对我有用的解决方案是扩展搜索模式以包含与utf-16版本匹配的搜索模式并搜索两种模式之一:

    grep -riPa . -e "pattern|p.a.t.t.e.r.n."
    

    就可能的模式而言,这当然是非常有限的。

  2. grep还有其他类似ugrepripgrep可以处理文件的程序utf-16。我最终使用了ripgrep从 18.04 开始的标准 Ubuntu 软件包存储库中提供的程序:

    rg -i "pattern"  
    

这里对替代方案进行了很好的讨论:https://stackoverflow.com/questions/3752913/grepping-binary-files-and-utf16其中一种有趣的方法是尝试将搜索模式转换为utf-16并将其输入到grep。但是,我无法让它工作。

相关内容