为什么在 Shell (Bash) 中“字符类”应该优先于“字符范围”?

为什么在 Shell (Bash) 中“字符类”应该优先于“字符范围”?

Linux 命令行(书 - 页数 47)说:

...您必须非常小心它们[字符范围],因为除非正确配置,否则它们不会产生预期的结果。目前,您应该避免使用它们并使用字符类。

除此之外,这本书没有给出任何理由。

问题 - 1:那么,究竟为什么应该字符类(例如,,,[:alnum:]等)优先于[:alpha:][:digit:]字符范围(例如,,,[a-z]等)?[A-Z][0-9]

问题2:代表[:alpha:], [a-z],[A-Z]其他语言的大写和小写字母? 同样,是否[:digit:]也包括来自其他语言的数字?如果它们匹配的话。

(我知道有两个问题,但在本例中,它们几乎是相互关联的,IMO。)

答案1

根据bash联机帮助页,LC_COLLATE环境变量会影响字符范围,正如 Hauke Laging 的回答一样:

LC_COLLATE 此变量确定对路径名扩展结果进行排序时使用的排序规则,并确定范围表达式、等价类以及路径名扩展和模式匹配中的排序序列的行为。

另一方面,LC_CTYPE影响字符类别:

LC_CTYPE该变量确定路径名扩展和模式匹配中字符的解释以及字符类的行为。

这意味着什么两个都如果您在英语、从左到右、拉丁字母、阿拉伯数字的环境中思考,那么这些情况可能会出现问题。

如果您真的很合适,并且/或者正在为多语言环境编写脚本,那么最好确保您在匹配文件时知道您的语言环境变量是什么,或者确保您在一个完全通用的方式。

但是,除非您学过语言学,否则很难预见某些情况。

但是,我不知道使用拉丁语的语言环境会改变命令字母,所以 [az] 可以。那里拉丁字母的扩展,以不同的方式整理连字和变音符号。不过,这里有一个小实验:

mkdir /tmp/test
cd /tmp/test
export LC_CTYPE=de_DE.UTF-8
export LC_COLLATE=de_DE.UTF-8
touch Grüßen
ls G* # This says ‘Grüßen’
ls *[a-z]en # This says nothing!
ls *[a-zß]en # This says ‘Grüßen’
ls Gr[a-z]*en # This says nothing!

这很有趣:至少对于德语来说,像 ü 这样的变音符号和像 ß 这样的连字都不会折叠成拉丁字符。 (要么那样,要么我搞砸了区域设置更改!)

当然,这可能对您不利,如果您尝试查找以字母开头的文件名,请使用[a-z]*并将其应用于以“Ä”开头的文件。

答案2

至少在 OS X 上使用 bash 4.2 时,UTF-8 语言环境似乎使用 ASCII 排序规则,但 ISO 8859-1 语言环境在某些情况下不使用:

$ LC_ALL=en_US.UTF-8 tr A-C 1-9 <<< B
2
$ LC_ALL=en_US.ISO8859-1 tr A-C 1-9 <<< B
6
$ LC_ALL=en_US.UTF-8 grep [A-Z] <<< ä
$ LC_ALL=en_US.ISO8859-1 grep [A-Z] <<< ä
ä

在某些环境中,UTF-8 语言环境还使用不同的排序规则。

[:upper:] 和 [:lower:] 在许多语言环境中还包含非 ASCII 字符。如果您只想匹配 ASCII 字符,请使用如下内容:

LC_ALL=C tr a-zA-Z n-za-mN-ZA-M

如果 LC_ALL 已设置为其他值,则 LC_COLLATE=C 或 LANG=C 将不起作用。

答案3

“其他语言”,就是这样。不同的区域设置可能有不同的排序顺序。因此从理论上讲,这可能a-z与另一个区域设置不同。如果您想要匹配所有内容,范围就会变得困难。第一个字符是什么,最后一个字符是什么?

openSUSE 的人在检查用户名/密码时对此非常偏执,他们这样做:[abcdefghi...]

我从未想过其他语言/字符集中的数字。有趣的一点。

相关内容