猛击不如预期


8

一个作业问题:

将所有文件名与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”?


正确下对我的作品mksh的外壳,但没有bash --posix,所以得是对bash`一些具体的规则
谢尔盖Kolodyazhnyy

@Serg,请注意,除C语言环境外,POSIX未指定[AZ]的行为。mksh例如,zsh与的[A-Z]不匹配É。ksh93的[A-Z]比赛在,É但没有在h
斯特凡Chazelas

Answers:


9

这是一个语言环境问题。在您的语言环境中,[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

@ heemayl,no LC_ALL=C ls [a-z]*[^A-Z]不会仅影响ls的语言环境,而不会影响Shell用于扩展glob或解析该命令行的语言环境。
斯特凡Chazelas

您无需导出LC_xxx就可以将其应用于全局,但这将是更可取的,这样ls可以获得相同的语言环境。
斯特凡Chazelas

1
请注意,在一个字符集为例如GB18030的语言环境中,使用LC_ALL = C方法,它将无法在一个名为test-鏏例如的文件上进行匹配,因为一旦将字符集更改为C语言环境的字符集,它将变为<0xe7>A。IOW,当更改LC_CTYPE时,您得到了不同的字符。
斯特凡Chazelas

1
请注意,我怀疑OP的语言环境中的[AZ]覆盖范围远大于AbBcC ... zZ。它可能也有éÁ(但可能没有Ź)。IOW,[A-Z]在C语言环境之外使用几乎没有意义。
斯特凡Chazelas

@StéphaneChazelas感谢您的出色反馈。答案已更新。我相信我已经考虑到了一切。
xhienne '17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.