[[email protected] ~]$ export PS4='$LINENO + '
[[email protected] ~]$ trouble
5 + number=1
7 + '[' 1 = 1 ']'
8 + echo 'Number is equal to 1.'
Number is equal to 1.
Выполнить трассировку только выбранного фрагмента сценария можно с помощью команды set с параметром -x:
#!/bin/bash
# trouble: сценарий для демонстрации распространенных видов ошибок
number=1
set -x # Включить трассировку
if [ $number = 1 ]; then
echo "Number is equal to 1."
else
echo "Number is not equal to 1."
fi
set +x # Выключить трассировку
Здесь мы использовали команду set с параметром -x, чтобы включить трассировку, и с параметром +x, чтобы выключить ее. Этот прием используется для исследования сразу нескольких проблемных фрагментов в сценарии.
Исследование значений в процессе выполнения
Часто вместе с трассировкой полезно выводить содержимое переменных, чтобы иметь более полное представление о действиях сценария. Обычно для этого используются дополнительные инструкции echo:
#!/bin/bash
# trouble: сценарий для демонстрации распространенных видов ошибок
number=1
echo "number=$number" # ОТЛАДКА
set -x # Включить трассировку
if [ $number = 1 ]; then
echo "Number is equal to 1."
else
echo "Number is not equal to 1."
fi
set +x # Выключить трассировку
В этом тривиальном примере мы просто вывели значение переменной number и отметили дополнительную строку комментарием, чтобы в будущем упростить ее поиск и удаление. Подобный прием особенно полезен при исследовании поведения циклов и арифметических операций в сценариях.
Заключительное замечание
В этой главе мы рассмотрели несколько проблем, с которыми можно столкнуться в процессе разработки сценариев. Конечно, таких проблем несоизмеримо больше. Приемы, описанные здесь, помогут вам в поиске наиболее распространенных видов ошибок. Отладка — это искусство предотвращения ошибок (за счет постоянного тестирования в ходе разработки) и их поиска (путем эффективного использования приемов трассировки), которое дается только с опытом.
31. Управление потоком выполнения: ветвление с помощью case
В этой главе мы продолжим знакомство с инструментами управления потоком выполнения. В главе 28 мы сконструировали простое меню и реализовали логику обработки выбора его пунктов пользователем. Для этого использовалась серия команд if, выясняющих, какой из возможных вариантов выбран. Такие конструкции часто можно увидеть в программах, причем так часто, что в некоторых языках программирования (включая командную оболочку) был реализован механизм управления потоком выполнения для случаев с множеством альтернативных вариантов.
case
Командная оболочка bash поддерживает составную команду выбора из нескольких вариантов, которая называется case. Она имеет следующий синтаксис:
case слово in
[шаблон [| шаблон]...) команды ;;]...
esac
Взгляните еще раз, как программа read-menu из главы 28 обрабатывает выбор пользователя:
#!/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 точно так же, как пути механизмом подстановки. Шаблоны завершаются символом ). В табл. 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." ;;