Bash grep中的Unicode字符识别

Bash grep中的Unicode字符识别,bash,unicode,cygwin,Bash,Unicode,Cygwin,我发现了一个非常奇怪的行为,我想知道是否有人知道是什么导致了它。解释的时间很长,所以谢谢你的耐心。 我正在windows环境中运行一个bash脚本,通过cygwin调用。 在它里面,我基本上想在一个文件中找到一个字符,这个字符在我定义的特定字母表中找不到,非常简单。 因为我使用的是Unicode字符,所以我设置了 $ LC_ALL=en_US.UTF-8 我有一个名为“files.txt”的文件,其中包含以下内容: $ cat files.txt đđđ üüü 我使用普通字符和Unicod

我发现了一个非常奇怪的行为,我想知道是否有人知道是什么导致了它。解释的时间很长,所以谢谢你的耐心。 我正在windows环境中运行一个bash脚本,通过cygwin调用。 在它里面,我基本上想在一个文件中找到一个字符,这个字符在我定义的特定字母表中找不到,非常简单。 因为我使用的是Unicode字符,所以我设置了

$ LC_ALL=en_US.UTF-8
我有一个名为“files.txt”的文件,其中包含以下内容:

$ cat files.txt
đđđ
üüü
我使用普通字符和Unicode字符定义字母表:

$ ALPHABET=$(printf %s {a..z} $(printf "\u0161") $(printf "\u010d"))
$ echo $ALPHABET
abcdefghijklmnopqrstuvwxyzšč
$ grep -v "^[$ALPHABET ]*$" files.txt
đđđ
üüü
正如所料。这个问题尤其出现在字符“ñ”(\u00d1)与“đ”(\u0111)的组合中:

有趣的是,只有在添加其他Unicode字符的情况下才会发生这种情况。一个常量是“ñ”必须存在

$ ALPHABET=$(printf %s {a..z} $(printf "\u00d1"))
$ echo $ALPHABET
abcdefghijklmnopqrstuvwxyzÑ
$ grep -v "^[$ALPHABET ]*$" files.txt
đđđ
üüü
$ ALPHABET=$(printf %s {a..z} $(printf "\u00d1") a $(printf "\u010d"))
$ echo $ALPHABET
abcdefghijklmnopqrstuvwxyzÑač
$ grep -v "^[$ALPHABET ]*$" files.txt
üüü
$ ALPHABET=$(printf %s {a..z} $(printf "\u010d") $(printf "\u00d1"))
$ echo $ALPHABET
abcdefghijklmnopqrstuvwxyzčÑ
$ grep -v "^[$ALPHABET ]*$" files.txt
üüü
$ ALPHABET=$(printf %s {a..z} $(printf "\u010d") $(printf "\u010c"))
$ echo $ALPHABET
abcdefghijklmnopqrstuvwxyzčČ
$ grep -v "^[$ALPHABET ]*$" files.txt
đđđ
üüü
$ ALPHABET=$(printf %s {a..z} $(printf "\u00d1") $(printf "\u00e1") $(printf "\u00c9"))
$ echo $ALPHABET
abcdefghijklmnopqrstuvwxyzÑáÉ
$ grep -v "^[$ALPHABET ]*$" files.txt
đđđ
üüü
我尝试了各种组合和排序,但无法准确指出哪种类型的组合决定了grep决定“đ”在模式中。我发现的唯一一件事是,除了其他一些额外的unicode字符的排列方式外,“ñ”也必须存在,但我不知道这种其他排列方式必须是什么

最后,如果我直接在cygwin终端中执行这些命令,事情就会正常工作。只有通过Windows批处理“C:\Tools\cygwin64\bin\bash.exe%script%”调用此脚本的执行时,才会发生此行为


有人知道会发生什么吗?谢谢,非常感谢。

感谢@n.m.提供了正确的答案! 实际上,LC_必须全部出口。一旦我这样做了,行为就像预期的那样,在我尝试的所有不同配置中,đ都没有被识别为模式的一部分。 所以不是

$ LC_ALL=en_US.UTF-8
使用:

我不知道为什么会这样(因为所有命令都在同一个终端中顺序运行),但我想如果这就是它工作的原因,那么就继续吧。
感谢大家的帮助和建议,我意识到环境不容易复制。

感谢@n.m.提供了正确的答案! 实际上,LC_必须全部出口。一旦我这样做了,行为就像预期的那样,在我尝试的所有不同配置中,đ都没有被识别为模式的一部分。 所以不是

$ LC_ALL=en_US.UTF-8
使用:

我不知道为什么会这样(因为所有命令都在同一个终端中顺序运行),但我想如果这就是它工作的原因,那么就继续吧。
感谢您的帮助和建议,我意识到环境不容易复制。

尝试将输出重定向到文件。问题还在发生吗?这可能只是航站楼的问题。谢谢你的建议。输出到文件时的相同行为。事实上,grep最初是作为“if grep-q…”执行的,因此终端输出从未涉及。
đ
đ
在UTF-8下都有相同的第二个字节(
0x91
),因此可能是匹配的字节而不是字符。也许可以检查它执行的区域设置?当
LC\u ALL=“en\u GB.UTF-8”
时,你的例子对我来说很好,但是当
LC\u ALL=“C”
时,你的例子失败了。谢谢@nj\u。这两个字符具有相同的第二个字节,这一点很好。但是
š
á
也共享相同的第二个字节(
c5a1
c3a1
),我无法用它们重现错误。我会继续调查。你在哪里设置了LC_ALL?尝试将输出重定向到一个文件。问题还在发生吗?这可能只是航站楼的问题。谢谢你的建议。输出到文件时的相同行为。事实上,grep最初是作为“if grep-q…”执行的,因此终端输出从未涉及。
đ
đ
在UTF-8下都有相同的第二个字节(
0x91
),因此可能是匹配的字节而不是字符。也许可以检查它执行的区域设置?当
LC\u ALL=“en\u GB.UTF-8”
时,你的例子对我来说很好,但是当
LC\u ALL=“C”
时,你的例子失败了。谢谢@nj\u。这两个字符具有相同的第二个字节,这一点很好。但是
š
á
也共享相同的第二个字节(
c5a1
c3a1
),我无法用它们重现错误。我会继续调查。你在哪里设置了LC_ALL?据我所知,这个问题似乎是因为printf是bashshell的本机命令,而grep不是,并且作为一个新进程分叉。同样地,设置LC_ALL适用于printf命令(如回送字母表时所示),但不适用于grep,除非它被导出。再次感谢@n.m.建议您试试这个!据我所知,问题似乎是因为printf是bashshell的本机命令,而grep不是,forks是一个新进程。同样地,设置LC_ALL适用于printf命令(如回送字母表时所示),但不适用于grep,除非它被导出。再次感谢@n.m.建议您试试这个!
$ export LC_ALL=en_US.UTF-8