使用 CJK 字符时 grep 行为很奇怪吗?(bash)

使用 CJK 字符时 grep 行为很奇怪吗?(bash)

grep 无法匹配某些包含 CJK 字符的字符串。例如。

  1. 创建一个包含以下内容的文本文件:
==ShellType.サモナ\u30FC==
  1. 使用 grep。
    >> grep "ShellType.サモナ\u30FC" test.txt
    (empty output)
    >> grep "ShellType.サモナ.*\u30FC" test.txt
    ==ShellType.サモナ\u30FC==

这是 grep 错误还是 CJK 字符需要特殊处理?
如何使用 grep 或其他可靠工具正确搜索 CJK 字符串?

系统:Ubuntu 20.04
GNU bash,版本 5.0.17(1)-release(x86_64-pc-linux-gnu)
grep(GNU grep)3.4

答案1

它与 CJK 无关。您可以使用-o来(或多或少)查看\u中的实际含义grep

[tom@ideapad ~]$ cat /tmp/meh 
==ShellType.サモナ\u30FC==
[tom@ideapad ~]$ grep -o '\u' /tmp/meh 
u
[tom@ideapad ~]$ grep -o '.\u' /tmp/meh 
\u
[tom@ideapad ~]$ grep -o '.*\u' /tmp/meh 
==ShellType.サモナ\u
[tom@ideapad ~]$ grep -o '.*.*\u' /tmp/meh 
==ShellType.サモナ\u
[tom@ideapad ~]$ grep -o '==ShellType.サモナ.*\u' /tmp/meh
==ShellType.サモナ\u
[tom@ideapad ~]$ grep -o '==ShellType.サモナ.\u' /tmp/meh
==ShellType.サモナ\u

请注意,我一直使用单引号\,因为双引号会使事情变得更加复杂。执行您(似乎)想要的 grep 的正确方法是:

[tom@ideapad ~]$ grep -o '==ShellType\.サモナ\\u' /tmp/meh 
==ShellType.サモナ\u
[tom@ideapad ~]$ grep -o "==ShellType\\.サモナ\\\\u" /tmp/meh 
==ShellType.サモナ\u

据我所知,grep 并不\u30FC像 shell 那样将其视为 unicode 字符(无论进一步转义如何)printf。要真正使用其代码点来 grep 一个字符,您可以让 shell 先使用 ANSI-C 引用来扩展它(尽管它可能并非在每个 POSIX shell 中都有效):

[tom@ideapad ~]$ printf '\u30FC' > /tmp/heh
[tom@ideapad ~]$ grep $'\u30FC' /tmp/heh 

PS 值得一提的是,虽然 ANSI-C 引用在其语法中使用单引号,但这并不意味着它在代码点扩展以外的部分像单引号一样工作:

[tom@ideapad ~]$ grep -o $'==ShellType\.サモナ\\u' /tmp/meh 
[tom@ideapad ~]$ grep -o $'==ShellType\\.サモナ\\\\u' /tmp/meh 
==ShellType.サモナ\u

相关内容