Bash Globbing não como esperado

8

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

Match all filenames with 2 or more characters that start with a lower case letter, but do not end with an upper case letter.

Eu não entendo porque 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]

Saída:

aa  ha

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

    
por DarkHeart 19.01.2017 / 01:21

1 resposta

9

Este é um problema localidade . Em sua localidade, [A-Z] se expande para algo como [AbBcZ...zZ] (mais provavelmente outros como caracteres acentuados), portanto [^A-Z] significa "arquivos que terminam com a " no seu exemplo (e apenas no seu exemplo). / p>

Se você quiser evitar essa surpresa, uma maneira é definir LC_COLLATE=C , pois o agrupamento é a parte das configurações de localidade que é responsável pela ordem de classificação. Além disso, esvazie LC_ALL se 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: [:lower:] em vez de [a-z] e [:upper:] em vez de [A-Z] .

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

Ou use a opção globasciiranges 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
    
por 19.01.2017 / 01:42