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 точно так же, как пути механизмом подстановки. Шаблоны завершаются символом ). В табл. 31.1 перечислены некоторые допустимые шаблоны.
Таблица 31.1. Примеры шаблонов в команде case
Шаблон
Описание
a)
Соответствует, если слово содержит a
[[:alpha:]])
Соответствует, если слово содержит единственный алфавитный символ
???)
Соответствует, если слово содержит ровно три символа
*.txt)
Соответствует, если слово заканчивается символами .txt
*)
Соответствует любому значению слова. Считается хорошей практикой включать этот шаблон в команду 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, предложив пользователю выбирать пункты меню вводом букв, а не цифр. Обратите внимание, что новые шаблоны позволяют вводить буквы обоих регистров — верхнего и нижнего.
Заключительное замечание
Команда case является удобным дополнением к нашей коллекции приемов программирования. Как будет показано в следующей главе, она отлично подходит для решения некоторых видов задач.
32. Позиционные параметры
Во всех предыдущих наших программах отсутствовала одна особенность — возможность принимать и обрабатывать параметры и аргументы командной строки. В этой главе мы исследуем эту возможность и позволим нашим программам обращаться к содержимому командной строки.
Доступ к командной строке
Командная оболочка поддерживает множество переменных, которые называются позиционными параметрами и содержат отдельные слова из командной строки. Эти переменные имеют имена от 0 до 9. Продемонстрируем их:
#!/bin/bash
# posit-param: сценарий для просмотра параметров командной строки
echo "
$0 = $0
$1 = $1
$2 = $2
$3 = $3
$4 = $4
$5 = $5
$6 = $6
$7 = $7
$8 = $8
$9 = $9
"
Этот очень простой сценарий выводит значения переменных с именами от $0 до $9. Запустим его без аргументов командной строки:
[[email protected] ~]$ posit-param
$0 = /home/me/bin/posit-param
$1 =
$2 =
$3 =
$4 =
$5 =
$6 =
$7 =
$8 =
$9 =
Даже в отсутствие аргументов переменная $0 всегда содержит первый элемент командной строки — путь к файлу выполняемой программы. Давайте передадим сценарию несколько аргументов:
[[email protected] ~]$ posit-param a b c d
$0 = /home/me/bin/posit-param
$1 = a
$2 = b
$3 = c
$4 = d
$5 =
$6 =
$7 =
$8 =
$9 =
ПРИМЕЧАНИЕ
В действительности, если использовать механизм подстановки параметров, можно получить доступ более чем к девяти параметрам. Чтобы указать число больше девяти, следует заключить его в фигурные скобки; например, ${10}, ${55}, ${211} и т.д.
Определение числа аргументов
Командная оболочка поддерживает также переменную $#, хранящую число аргументов командной строки:
#!/bin/bash
# posit-param: сценарий для просмотра параметров командной строки
echo "
Number of arguments: $#
$0 = $0
$1 = $1
$2 = $2
$3 = $3
$4 = $4
$5 = $5
$6 = $6
$7 = $7
$8 = $8
$9 = $9
"
Результат:
[[email protected] ~]$ posit-param a b c d
Number of arguments: 4
$0 = /home/me/bin/posit-param
$1 = a
$2 = b
$3 = c
$4 = d
$5 =
$6 =
$7 =
$8 =
$9 =
shift — доступ к множеству аргументов
Но как быть, если программе передается большое число аргументов, как в следующем примере:
[[email protected] ~]$ posit-param *
Number of arguments: 82
$0 = /home/me/bin/posit-param
$1 = addresses.ldif
$2 = bin
$3 = bookmarks.html
$4 = debian-500-i386-netinst.iso
$5 = debian-500-i386-netinst.jigdo
$6 = debian-500-i386-netinst.template
$7 = debian-cd_info.tar.gz
$8 = Desktop
$9 = dirlist-bin.txt
В системе, где выполнялся этот пример, механизм подстановки развернул символ * в 82 аргумента. Как обработать такое количество? Командная оболочка предусматривает решение и для подобных случаев, правда, следует отметить, что изяществом оно не отличается. Команда shift выполняет «сдвиг» параметров к началу списка. Фактически, используя shift, можно обойтись единственной переменной-параметром (помимо $0, которая никогда не изменяется).
#!/bin/bash
# posit-param2: сценарий вывода всех аргументов
count=1
while [[ $# -gt 0 ]]; do
echo "Argument $count = $1"
count=$((count + 1))
shift
done
Каждый раз, когда выполняется команда shift, значение $2 перемещается в $1, значение $3 перемещается в $2 и т.д. Значение $# при этом уменьшается на 1.
В программе posit-param2 мы создали цикл, проверяющий число оставшихся аргументов и продолжающийся до тех пор, пока оно не уменьшится до нуля. Цикл выводит текущий аргумент, в каждой итерации увеличивает счетчик обработанных аргументов count и, наконец, выполняет shift, чтобы загрузить в $1 следующий аргумент. Вот как работает эта программа:
[[email protected] ~]$ posit-param2 a b c d
Argument 1 = a
Argument 2 = b
Argument 3 = c
Argument 4 = d
Простые приложения
Даже без команды shift можно писать полезные приложения, использующие позиционные параметры. Например, ниже приводится простая программа получения информации о файле:
#!/bin/bash
# file_info: простая программа получения информации о файле
PROGNAME=$(basename $0)
if [[ -e $1 ]]; then
echo -e "nFile Type:"
file $1
echo -e "nFile Status:"
stat $1
else
echo "$PROGNAME: usage: $PROGNAME file" >&2
exit 1
fi
Эта программа выводит тип указанного файла (определяется с помощью команды file) и его состояние (командой stat). Интересной особенностью программы является переменная PROGNAME. Ей присваивается результат выполнения команды basename $0. Команда basename удаляет начальную часть из пути к файлу, оставляя только базовое имя. В данном примере basename удалит начальную часть из параметра $0, хранящего полный путь к данной программе. Такой результат удобно использовать для конструирования сообщений, например, о правилах использования программы. При подобном подходе можно переименовать сценарий, и при выводе сообщений новое имя программы будет использоваться автоматически.
Использование позиционных параметров в функциях
Позиционные параметры используются для передачи аргументов не только в сценарии, но и в функции командной оболочки. Для демонстрации преобразуем сценарий file_info в функцию:
file_info () {
# file_info: функция для вывода информации о файле
if [[ -e $1 ]]; then
echo -e "nFile Type:"
file $1
echo -e "nFile Status:"
stat $1
else
echo "$FUNCNAME: usage: $FUNCNAME file" >&2
return 1
fi
}
Теперь, если сценарий, включающий функцию file_info, вызовет ее с именем файла в аргументе, аргумент будет передан в функцию.