Bash 通配符不符合预期

Bash 通配符不符合预期

一个家庭作业问题:

匹配所有包含 2 个或更多以小写字母开头但不以大写字母结尾的字符的文件名。

我不明白为什么我的解决方案不起作用。

所以我执行了以下操作:

touch aa
touch ha
touch ah
touch hh
touch a123e
touch hX
touch Ax

ls [a-z]*[!A-Z]

输出:

aa  ha

我的问题:为什么它不匹配“ah”、“hh”或“a123e”?

答案1

这是一个语言环境问题。在您的语言环境中,[A-Z]扩展为类似的内容[AbBcZ...zZ](可能还加上其他重音字符),因此[^A-Z]实际上意味着“在您的示例中以”结尾的文件a(并且仅在您的示例中)。

如果您想避免这种意外,一种方法是设置,LC_COLLATE=C 因为排序规则是区域设置中负责排序顺序的部分。另外,LC_ALL如果已设置,则为空,因为它会优先。

$ ls [a-z]*[^A-Z]
aa  ha

$ ( LC_ALL=; LC_COLLATE=C; ls [a-z]*[^A-Z] )
a123e  aa  ah  ha  hh

或者,更好的是,最好不要更改您的区域设置并使用适当的类:[:lower:]代替[a-z][:upper:]代替[A-Z]

$ ls [[:lower:]]*[^[:upper:]]
a123e  aa  ah  ha  hh

或者使用 bash 的globasciiranges选项:

$ shopt -s globasciiranges
$ ls [a-z]*[^A-Z]
a123e  aa  ah  ha  hh

$ shopt -u globasciiranges
$ ls [a-z]*[^A-Z]
aa  ha

相关内容