Bash Globbing não como o esperado

8

Esta é uma pergunta de lição de casa:

Combine todos os nomes de arquivos com 2 ou mais caracteres que começam com uma letra minúscula, mas não terminam com uma letra maiúscula.

Não entendo por que minha solução não está funcionando.

Então eu executei o abaixo:

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

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

Resultado:

aa  ha

Minha pergunta: por que não corresponde a "ah", "hh" ou "a123e"?

DarkHeart
fonte
Funciona para mim corretamente no mkshshell, mas não bash --posix, então deve haver alguma regra específica para o bash` #
Sergiy Kolodyazhnyy
@Erg, observe que o comportamento de [AZ] não é especificado pelo POSIX, exceto no código C. mkshcomo zsh's [A-Z]não corresponde em Épor exemplo. As [A-Z]partidas de ksh93 estão ativadas, Émas não ativadas h.
Stéphane Chazelas

Respostas:

9

Este é um problema de localidade . No seu código de idioma, [A-Z]expande para algo como [AbBcZ...zZ](e provavelmente outros como caracteres acentuados), portanto, [^A-Z]na verdade significa "arquivos que terminam coma " no seu exemplo (e somente no seu exemplo).

Se você deseja evitar essa surpresa, uma maneira é definir, LC_COLLATE=C pois o agrupamento faz parte das configurações de localidade responsáveis ​​pela ordem de classificação. Além disso, esvazie LC_ALLse estiver definido, pois isso teria precedência.

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

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

Ou, melhor, provavelmente é preferível não alterar as configurações de localidade e usar as classes apropriadas: em [:lower:]vez de [a-z]e em [:upper:]vez de [A-Z].

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

Ou use a globasciirangesopção do 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
fonte
@heemayl, no LC_ALL=C ls [a-z]*[^A-Z]afetaria apenas a lslocalidade de, não a localidade usada pelo shell para expandir a glob ou analisar essa linha de comando.
Stéphane Chazelas
Você não precisa exportar LC_xxxpara que se aplique à glob, mas seria preferível que o ls obtenha o mesmo código de idioma.
Stéphane Chazelas
1
Observe que em um código de idioma em que o conjunto de caracteres é GB18030, por exemplo, com a abordagem LC_ALL = C, ele falharia em corresponder a um arquivo chamado, test-鏏por exemplo, porque depois que você altera o conjunto de caracteres para o código de idioma C, fica <0xe7>A. IOW, ao alterar LC_CTYPE, você obtém caracteres diferentes.
Stéphane Chazelas
1
Observe que eu suspeito que [AZ] na localidade do OP cubra mais do que AbBcC ... zZ. Provavelmente também tem é, Á(mas provavelmente nãoŹ ). IOW, usar [A-Z]faz pouco sentido fora do código C.
Stéphane Chazelas
@ StéphaneChazelas Obrigado pelo excelente feedback. Resposta atualizada. Eu acredito que levei tudo em consideração.
xhienne