ds () {
echo "Disk Space Utilization For $HOSTNAME"
df -h
}
Заключительное замечание
В этой главе мы познакомились с широко применяемым методом проектирования программ сверху вниз и увидели, как можно поэтапно развивать функции командной оболочки. Мы также научились при помощи локальных переменных делать функции независимыми от других функций и программ, в которых они находятся. Функции можно делать переносимыми и пригодными для повторного использования во множестве программ, что поможет сэкономить массу времени.
27. Управление потоком выполнения: ветвление при помощи if
В предыдущей главе мы столкнулись с проблемой. Как помочь сценарию адаптировать свое поведение в зависимости от привилегий пользователя, запустившего его? Для решения проблемы нам необходим некий способ «изменить направление» выполнения сценария, опираясь на результаты проверки. Выражаясь языком программистов, нам нужен способ, обеспечивающий ветвление программы.
Рассмотрим простой пример логики, выраженный в псевдокоде, имитирующем язык компьютеров, но понятном человеку:
x = 5
Если x = 5, тогда:
Сказать «x равно 5».
Иначе:
Сказать «x не равно 5».
Это — пример ветвления. Если условие «x = 5?» верно, выполняется строка: «Сказать ‘x равно 5’». Иначе выполняется строка: «Сказать ‘x не равно 5’».
Использование if
В сценариях на языке командной оболочки описанную выше логику можно реализовать так:
x=5
if [ $x = 5 ]; then
echo "x equals 5."
else
echo "x does not equal 5."
fi
А если то же самое можно выполнить непосредственно в командной строке, получается немного короче:
[[email protected] ~]$ x=5
[[email protected] ~]$ if [ $x = 5 ]; then echo "equals 5"; else echo "does not equal 5"; fi
equals 5
[[email protected] ~]$ x=0
[[email protected] ~]$ if [ $x = 5 ]; then echo "equals 5"; else echo "does not equal 5"; fi
does not equal 5
В этом примере мы выполнили команду дважды. Первый раз со значением 5 в переменной x, что привело к выводу строки equals 5, и второй раз со значением 0 в переменной x, что привело к выводу строки not equal 5.
Инструкция if имеет следующий синтаксис:
if команды; then
команды
[elif команды; then
commands...]
[else
команды]
fi
где команды — это список команд. На первый взгляд такой синтаксис выглядит запутанным. Но прежде чем прояснить его, посмотрим, как командная оболочка определяет, успешно или нет выполнена команда.
Код завершения
Команды (включая сценарии и функции, написанные нашими собственными руками) по завершении работы возвращают системе значение, которое называют кодом завершения (exit status). Это значение — целое число в диапазоне от 0 до 255 — сообщает об успешном или неуспешном завершении команды. По соглашениям значение 0 служит признаком успешного завершения, а любое другое — неуспешного. Командная оболочка поддерживает переменную, посредством которой можно определить код завершения. Например:
[[email protected] ~]$ ls -d /usr/bin
/usr/bin
[[email protected] ~]$ echo $?
0
[[email protected] ~]$ ls -d /bin/usr
ls: cannot access /bin/usr: No such file or directory
[[email protected] ~]$ echo $?
2
В этом примере мы дважды выполнили команду ls. В первый раз команда выполнилась благополучно. Если вывести значение переменной $?, можно увидеть, что оно равно 0. Во второй раз команда ls сообщила об ошибке, а переменная $? содержала значение 2, указывающее, что команда столкнулась с ошибкой. Одни команды используют разные коды завершения, чтобы сообщить о характере ошибки, тогда как другие, столкнувшись с любой ошибкой, просто возвращают значение 1. Страницы справочного руководства часто включают раздел с заголовком «Exit Status» («Коды завершения»), описывающий возвращаемые коды. Однако 0 всегда служит признаком успешного выполнения.
Командной оболочкой поддерживаются две чрезвычайно простые встроенные команды, которые просто завершаются с кодом 0 или 1. Команда true всегда завершается с признаком успеха, а команда false — всегда с признаком ошибки:
[[email protected] ~]$ true
[[email protected] ~]$ echo $?
0
[[email protected] ~]$ false
[[email protected] ~]$ echo $?
1
Эти команды можно использовать для исследования особенностей работы инструкции if. Инструкция if в действительности просто оценивает код завершения команды:
[[email protected] ~]$ if true; then echo "It's true."; fi
It's true.
[[email protected] ~]$ if false; then echo "It's true."; fi
[[email protected] ~]$
Команда echo "It's true." выполняется, только если команда, следующая за if, завершается успешно, и не выполняется, если команда, следующая за if, завершается с признаком ошибки. Если за if следует список команд, успешность выполнения всего списка определяется по последней команде:
[[email protected] ~]$ if false; true; then echo "It's true."; fi
It's true.
[[email protected] ~]$ if true; false; then echo "It's true."; fi
[[email protected] ~]$
Команда test
Вне всяких сомнений, чаще всего с инструкцией if используется команда test. Команда test может выполнять различные проверки и сравнения. Она имеет две эквивалентные формы:
test выражение
и более популярную
[ выражение ]
где выражение возвращает истинное (true) или ложное (false) значение. Команда test возвращает код завершения 0, если выражение истинно, и код завершения 1, если выражение ложно.
Выражения для проверки файлов
В табл. 27.1 перечислены выражения, используемые для проверки файлов.
Таблица 27.1. Выражения для проверки файлов
Выражение
Истинно, если...
файл1 -ef файл2
файл1 и файл2 имеют одно и то же число индексного узла (inode; то есть два имени принадлежат жестким ссылкам, ссылающимся на один и тот же файл)
файл1 -nt файл2
файл1 новее файла файл2
файл1 -ot файл2
файл1 старше файла файл2
-b файл
файл существует и является специальным файлом блочного устройства
-с файл
файл существует и является специальным файлом символьного устройства
-d файл
файл существует и является каталогом
-e файл
файл существует
-f файл
файл существует и является обычным файлом
-g файл
файл существует и имеет атрибут set-group-ID (бит setgid)
-G файл
файл существует и принадлежит действующей группе
-k файл
файл существует и имеет атрибут «sticky bit»
-L файл
файл существует и является символической ссылкой
-O файл
файл существует и принадлежит действующему пользователю
-p файл
файл существует и является именованным каналом
-r файл
файл существует и доступен для чтения (имеет разрешение на чтение для действующего пользователя)
-s файл
файл существует и имеет размер больше нуля
-S файл
файл существует и является сетевым сокетом
-t дескриптор_файла
дескриптор_файла представляет файл, подключенный к терминалу. Это выражение можно использовать для проверки стандартных потоков ввода/вывода/ошибок
-u файл
файл существует и имеет атрибут setuid
-w файл
файл существует и доступен для записи (имеет разрешение на запись для действующего пользователя)
-x файл