Distinção entre maiúsculas e minúsculas no script de shell

10

Considere este script Bash:

#!/bin/bash
echo Enter any character
read char
case $char in
    [a-z]) echo Lower case letter
            ;;
    [A-Z]) echo Upper case letter
            ;;
    [0-9]) echo Number
            ;;
    ?) echo Special char
            ;;
    *) echo You entered more than one character 
            ;;
esac

Se eu digitar 'a', a saída será minúscula e o mesmo será para 'A' ... Como supero isso?

Ramana Reddy
fonte
Ao publicar um script, use o formato de código para manter o espaço em branco. Além disso, qual é a pergunta real? Eu não tenho certeza do que você quer dizer ...
AJefferiss
2
@ Arronical não há necessidade, o eco pode lidar com palavras reservadas echo if case then do.
terdon
Para um problema semelhante, mas lidando com a classificação, consulte askubuntu.com/questions/597924/…
Joe

Respostas:

20
#!/bin/bash
echo 'enter any character'
read char
case $char in
[[:lower:]]) echo 'lower case letter'
    ;;
[[:upper:]]) echo 'upper case letter'
    ;;
[0-9]) echo 'number'
    ;;
?) echo 'special char'
    ;;
*) echo 'u entered more than one char' 
    ;;
esac  

Para obter mais informações sobre a expressão regular em minúscula de [az] e a expressão regular em maiúscula de [AZ] no bash, consulte Por que a declaração de caso não diferencia maiúsculas de minúsculas quando o nocasematch está desativado? .

karel
fonte
6
Após isso, em vez de [0-9]você pode usar [[:digit:]]. Você pode encontrar mais exemplos man grepou classes de caracteres do Google posix .
Paddy Landau
21

O problema é que o intervalo de caracteres [a-z]na verdade inclui as letras maiúsculas. Isso é explicado no manual do bash :

Dentro de uma expressão entre colchetes, uma expressão de intervalo consiste em dois caracteres separados por um hífen. Corresponde a qualquer caractere único que classifique entre os dois caracteres, inclusive. No código de idioma C padrão, a sequência de classificação é a ordem de caracteres nativa; por exemplo, '[ad]' é equivalente a '[abcd]'. Em outros locais, a sequência de classificação não é especificada e '[ad]' pode ser equivalente a '[abcd]' ou '[aBbCcDd]' ou pode falhar em corresponder a qualquer caractere ou ao conjunto de caracteres que ele contém. as correspondências podem até ser erráticas. Para obter a interpretação tradicional das expressões entre colchetes, você pode usar o código do idioma 'C' configurando a variável de ambiente LC_ALL para o valor 'C'.

Ilustrar:

$ case B in [a-c]) echo YES;;  *) echo NO;; esac
YES
$ LC_ALL=C; case B in [a-c]) echo YES;; *) echo NO;; esac
NO

Então, o que acontece é que, na sua localidade (o que não é C), [a-c]é realmente [aAbBcC]. É por isso que você deve usar as classes de caracteres POSIX, como sugerido por @karel.

Terdon
fonte
4
Mais precisamente, você precisa definir LC_COLLATEcomo C, não há problema em outras configurações de localidade serem diferentes. Definir LC_COLLATEqualquer coisa, mas Craramente é uma boa ideia, mas infelizmente o Ubuntu faz isso (não é o único culpado de longe).
Gilles 'SO- stop be evil'