Table of Contents
case
Командная оболочка bash поддерживает составную команду выбора из нескольких вариантов, которая называется case. Она имеет следующий синтаксис:
case слово in [шаблон [| шаблон]...) команды ;;]... esac
Взгляните еще раз, как программа read-menu из статьи Чтение ввода с клавиатуры обрабатывает выбор пользователя:
#!/bin/bash # read-menu: программа вывода системной информации, управляемая с помощью меню clear echo " Please Select: 1. Display System Information 2. Display Disk Space 3. Display Home Space Utilization 0. Quit " read -p "Enter selection [0-3] > " if [[ "$REPLY" =~ ^[0-3]$ ]]; then if [[ "$REPLY" == 0 ]]; then echo "Program terminated." exit fi if [[ "$REPLY" == 1 ]]; then echo "Hostname: $HOSTNAME" uptime exit fi if [[ "$REPLY" == 2 ]]; then df -h exit fi if [[ "$REPLY" == 3 ]]; then if [[ "$(id -u)" -eq 0 ]]; then echo "Home Space Utilization (All Users)" du -sh /home/* else echo "Home Space Utilization ($USER)" du -sh "$HOME" fi exit fi else echo "Invalid entry." >&2 exit 1 fi
С помощью case можно сделать логику выбора немного проще:
#!/bin/bash # case-menu: программа вывода системной информации, управляемая с помощью меню clear echo " Please Select: 1. Display System Information 2. Display Disk Space 3. Display Home Space Utilization 0. Quit " read -p "Enter selection [0-3] > " case "$REPLY" in 0) echo "Program terminated." exit ;; 1) echo "Hostname: $HOSTNAME" uptime ;; 2) df -h ;; 3) if [[ "$(id -u)" -eq 0 ]]; then echo "Home Space Utilization (All Users)" du -sh /home/* else echo "Home Space Utilization ($USER)" du -sh "$HOME" fi ;; *) echo "Invalid entry" >&2 exit 1 ;; esac
Команда case берет значение слова – в данном примере значение переменной REPLY – и затем сопоставляет его с указанными шаблонами. Найдя соответствие, она выполняет команды, связанные с найденным шаблоном. После нахождения соответствия сопоставление с нижележащими шаблонами уже не производится.
Шаблоны
Шаблоны обрабатываются командой case точно так же, как пути механизмом подстановки. Шаблоны завершаются символом <html>)</html>. В таблице ниже перечислены некоторые допустимые шаблоны
Шаблон | Описание |
---|---|
<html>a)</html> | Соответствует, если слово содержит a |
<html>alpha) </html> | Соответствует, если слово содержит единственный алфавитный символ |
<html>???)</html> | Соответствует, если слово содержит ровно три символа |
<html>*.txt)</html> | Соответствует, если слово заканчивается символами .txt |
<html>*)</html> | Соответствует любому значению слова. Считается хорошей практикой включать этот шаблон в команду case последним, чтобы перехватывать любые значения слова, не соответствующие ни одному из предыдущих шаблонов, то есть, чтобы перехватывать любые недопустимые значения |
Следующий пример демонстрирует работу шаблонов:
#!/bin/bash read -p "enter word > " case "$REPLY" in [[:alpha:]]) echo "is a single alphabetic character." ;; [ABC][0-9]) echo "is A, B, or C followed by a digit." ;; ???) echo "is three characters long." ;; *.txt) echo "is a word ending in '.txt'" ;; *) echo "is something else." ;; esac
Мы можем объединить несколько шаблонов, перечислив их через символ вертикальной черты. В результате получается комбинированный условный шаблон, объединенный по «ИЛИ». Эта возможность может пригодиться, например, для обработки символов верхнего и нижнего регистров:
#!/bin/bash # case-menu: программа вывода системной информации,управляемая с помощью меню clear echo " Please Select: A. Display System Information B. Display Disk Space C. Display Home Space Utilization Q. Quit " read -p "Enter selection [A, B, C or Q] > " case "$REPLY" in q|Q) echo "Program terminated." exit ;; a|A) echo "Hostname: $HOSTNAME" uptime ;; b|B) df -h ;; c|C) if [[ "$(id -u)" -eq 0 ]]; then echo "Home Space Utilization (All Users)" du -sh /home/* else echo "Home Space Utilization ($USER)" du -sh "$HOME" fi ;; *) echo "Invalid entry" >&2 exit 1 ;; esac
Здесь мы изменили программу case-menu, предложив пользователю выбирать пункты меню вводом букв, а не цифр. Обратите внимание, что новые шаблоны позволяют вводить буквы обоих регистров – верхнего и нижнего.
Выполнение нескольких вариантов
В версиях bash до 4.0 команда case могла выполнить только один вариант, соответствующий совпавшему шаблону. После этого команда завершалась. Рассмотрим сценарий, проверяющий введенный символ:
#!/bin/bash # case4-1: проверка символа read -n 1 -p "Type a character > " echo case "$REPLY" in [[:upper:]]) echo "'$REPLY' is upper case." ;; [[:lower:]]) echo "'$REPLY' is lower case." ;; [[:alpha:]]) echo "'$REPLY' is alphabetic." ;; [[:digit:]]) echo "'$REPLY' is a digit." ;; [[:graph:]]) echo "'$REPLY' is a visible character." ;; [[:punct:]]) echo "'$REPLY' is a punctuation symbol." ;; [[:space:]]) echo "'$REPLY' is a whitespace character." ;; [[:xdigit:]]) echo "'$REPLY' is a hexadecimal digit." ;; esac
Вот как выглядит результат выполнения этого сценария:
Type a character > a 'a' is lower case.
В большинстве случаев сценарий прекрасно справляется со своей задачей, но терпит неудачу, если символ соответствует нескольким символьным классам POSIX. Например, символ a соответствует классам алфавитных символов и символов нижнего регистра, а также шестнадцатеричных цифр. В bash до версии 4.0 не было никакой возможности заставить case выполнить больше одной успешной проверки. Современные версии bash поддерживают дополнительную нотацию <html>;;&</html> в конце каждого варианта, которая используется, как показано ниже:
#!/bin/bash # case4-1: проверка символа read -n 1 -p "Type a character > " echo case "$REPLY" in [[:upper:]]) echo "'$REPLY' is upper case." ;;& [[:lower:]]) echo "'$REPLY' is lower case." ;;& [[:alpha:]]) echo "'$REPLY' is alphabetic." ;;& [[:digit:]]) echo "'$REPLY' is a digit." ;;& [[:graph:]]) echo "'$REPLY' is a visible character." ;;& [[:punct:]]) echo "'$REPLY' is a punctuation symbol." ;;& [[:space:]]) echo "'$REPLY' is a whitespace character." ;;& [[:xdigit:]]) echo "'$REPLY' is a hexadecimal digit." ;;& esac
Запустив этот сценарий, мы получим:
Type a character > a 'a' is lower case. 'a' is alphabetic. 'a' is a visible character. 'a' is a hexadecimal digit.
Дополнительный синтаксис <html>;;&</html> позволяет команде case продолжить проверку вместо простого завершения после первого найденного совпадения.