Bash Globbing не так, как ожидалось

8

Это является домашним заданием вопроса:

Сопоставьте все имена файлов с 2 или более символами, которые начинаются со строчной буквы, но не заканчиваются заглавной буквой.

Я не понимаю, почему мое решение не работает.

Поэтому я выполнил следующее:

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

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

Вывод:

aa  ha

Мой вопрос: почему он не соответствует "ах", "чч" или "a123e"?

Темное сердце
источник
У меня работает правильно под mkshоболочкой, но нет bash --posix, так что должно быть какое-то определенное правило для bash`
Сергей Колодяжный
@Serg, обратите внимание, что POSIX не определяет поведение для [AZ], за исключением языкового стандарта C. mkshнапример zsh, лайки [A-Z]не совпадают É. ksh93 в [A-Z]матчах на Éно не на h.
Стефан

Ответы:

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

Или используйте globasciirangesопцию bash :

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

$ shopt -u globasciiranges
$ ls [a-z]*[^A-Z]
aa  ha
xhienne
источник
@heemayl, no LC_ALL=C ls [a-z]*[^A-Z]влияет только на lsлокаль, а не на локаль, используемую оболочкой для расширения глобуса или анализа этой командной строки.
Стефан
Вам не нужно экспортировать LC_xxxего, чтобы применить к глобу, но это было бы предпочтительнее, поэтому ls получает ту же локаль.
Стефан
1
Обратите внимание, что в локали, где, например, charset - это GB18030, при подходе LC_ALL = C он не сможет соответствовать файлу, вызываемому, test-鏏например, потому что, как только вы измените кодировку на кодировку для локали C, она станет <0xe7>A. Итак, при изменении LC_CTYPE вы получаете разные символы.
Стефан
1
Обратите внимание, что я подозреваю, что [AZ] в локали OP охватывает больше, чем AbBcC ... zZ. Это , вероятно , также есть é, Á(но , вероятно , не Ź). IOW, использование [A-Z]имеет мало смысла вне языка Си.
Стефан
@ StéphaneChazelas Спасибо за отличные отзывы. Ответ обновлен. Я считаю, что я все учел.
Сиен