Sempre que você trabalha com intervalos de caracteres, é uma boa idéia inserir export LC_ALL=C (ou C.UTF-8 se você precisar de suporte para caracteres fora da faixa ASCII) no início do script, caso contrário, você pode se surpreender com o A-Z e a-z mean ...
Por exemplo:
$ unset LC_ALL
$ export LANG=en_US.UTF-8
$ [[ 'abc' = *[A-Z]* ]] && echo Match || echo No match
Match
$ export LC_ALL=C
$ [[ 'abc' = *[A-Z]* ]] && echo Match || echo No match
No match
O shell usa o intervalo [A-Z] para indicar todos os caracteres que classificam entre A e Z na localidade atual. No en_US locale b , classifica entre A e Z ; daí abc corresponde a *[A-Z]* . Por outro lado, no C locale b não classifica entre A e Z , porque os caracteres C locale são classificados estritamente de acordo com seu ponto de código.