Чувствительность к регистру в сценариях оболочки

10

Рассмотрим этот скрипт 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

Если я введу «а», то получится строчная буква , и то же самое для «А» ... Как мне преодолеть это?

Рамана Редди
источник
Когда вы публикуете скрипт, убедитесь, что вы используете формат кода, чтобы сохранить пробелы. Кроме того, каков реальный вопрос? Я не уверен, что вы имеете в виду ...
AJefferiss
2
@ Arronical не нужно, эхо может иметь дело с зарезервированными словами echo if case then do.
Terdon
По аналогичной проблеме, но имеющей дело с сортировкой, см. Askubuntu.com/questions/597924/…
Джо

Ответы:

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  

Для получения дополнительной информации о регулярном выражении строчных букв [az] и регулярном выражении верхних регистров [AZ] в bash см. Почему оператор регистра не чувствителен к регистру, когда nocasematch выключен? ,

Карел
источник
6
Исходя из этого, вместо [0-9]вас можно использовать [[:digit:]]. Вы можете найти больше примеров в классах символовman grep Google или posix .
Пэдди Ландау
21

Проблема в том, что диапазон символов на [a-z]самом деле включает буквы верхнего регистра. Это объясняется в руководстве по bash :

Внутри выражения в скобках выражение диапазона состоит из двух символов, разделенных дефисом. Он соответствует любому отдельному символу, который сортируется между двумя символами включительно. В языковом стандарте C по умолчанию последовательность сортировки соответствует порядку собственных символов; например, '[ad]' эквивалентно '[abcd]'. В других локалях последовательность сортировки не указана, и «[ad]» может быть эквивалентно «[abcd]» или «[aBbCcDd]» , либо может не совпадать с каким-либо символом или набором символов, которые он совпадения могут быть даже ошибочными. Чтобы получить традиционную интерпретацию скобочных выражений, вы можете использовать локаль 'C', установив переменную окружения LC_ALL в значение 'C'.

Проиллюстрировать:

$ 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

Итак, что происходит, так это то, что в вашей локали (а это не так C) на [a-c]самом деле [aAbBcC]. Вот почему вы должны использовать классы символов POSIX, как предложено @karel.

terdon
источник
4
Точнее, вам нужно установить LC_COLLATEна C, это нормально, если другие настройки локали будут другими. Установка LC_COLLATEна что угодно, но Cредко бывает хорошей идеей, но, к сожалению, Ubuntu делает это (это далеко не единственный виновник).
Жиль "ТАК - перестань быть злым"