Respect de la casse dans les scripts shell

10

Considérez ce 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

Si j'entre «a», la sortie est en minuscule , et c'est la même chose pour «A» ... Comment puis-je surmonter cela?

Ramana Reddy
la source
Lorsque vous publiez un script, assurez-vous d'utiliser le format de code pour conserver les espaces. Aussi, quelle est la vraie question? Je ne sais pas trop ce que tu veux dire ...
AJefferiss
2
@Arronical pas besoin, l'écho peut gérer les mots réservés echo if case then do.
terdon
Pour un problème similaire, mais traitant du tri, voir askubuntu.com/questions/597924/…
Joe

Réponses:

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  

Pour plus d'informations sur l'expression régulière en minuscules de [az] et l'expression régulière en majuscules de [AZ] dans bash, voir Pourquoi l'instruction case n'est-elle pas sensible à la casse lorsque nocasematch est désactivé? .

Karel
la source
6
Suite à cela, au lieu de [0-9]vous pouvez utiliser [[:digit:]]. Vous pouvez trouver plus d'exemples dans man grep, ou les classes de caractères Google posix .
Paddy Landau
21

Le problème est que la plage de caractères [a-z]comprend en fait les lettres majuscules. Ceci est expliqué dans le manuel bash :

Dans une expression entre crochets, une expression de plage se compose de deux caractères séparés par un trait d'union. Il correspond à tout caractère unique trié entre les deux caractères, inclus. Dans les paramètres régionaux C par défaut, la séquence de tri est l'ordre des caractères natifs; par exemple, «[ad]» équivaut à «[abcd]». Dans d'autres paramètres régionaux, la séquence de tri n'est pas spécifiée et '[ad]' peut être équivalent à '[abcd]' ou à '[aBbCcDd]' , ou il peut ne pas correspondre à aucun caractère, ou à l'ensemble de caractères qu'il les correspondances peuvent même être irrégulières. Pour obtenir l'interprétation traditionnelle des expressions entre crochets, vous pouvez utiliser les paramètres régionaux «C» en définissant la variable d'environnement LC_ALL sur la valeur «C».

Pour illustrer:

$ 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

Donc, ce qui se passe, c'est que dans votre région (ce qui n'est pas le cas C), [a-c]est en fait [aAbBcC]. C'est pourquoi vous devriez plutôt utiliser les classes de caractères POSIX comme suggéré par @karel.

terdon
la source
4
Plus précisément, vous devez configurer LC_COLLATEpour C, il est ok pour d' autres paramètres locaux , pour être différent. Le réglage LC_COLLATEsur n'importe quoi mais Cest rarement une bonne idée mais malheureusement Ubuntu le fait (ce n'est pas le seul coupable de loin).
Gilles 'SO- arrête d'être méchant'