Каждая команда вырабатывает код завершения — значение, передаваемое интерпретатору и показывающее, что произошло. Это небольшое целое число, которое устанавливается по соглашению. Так, нуль может означать "истину" (команда успешно завершена), а ненулевое значение трактуется как "ложь" (выполнение команды было неудачным). Обратите внимание на то, что выбранные здесь значения противоположны значениям истины и лжи в языке Си.
Поскольку ложь может представлять множество различных значений, причина неудачи обозначается кодом завершения по лжи. Например, команда grep возвращает 0, если произошло сопоставление, 1 — если сопоставления не было, и 2 — в случае ошибки в шаблоне или именах файлов. Каждая программа возвращает код завершения, хотя обычно нас не интересует его значение. Команда test
неординарна: ее единственное назначение состоит в передаче кода завершения. Она ничего не выводит и не изменяет файлы.
Интерпретатор хранит код завершения последней программы в переменной $?
:
$ cmp /usr/you/.profile /usr/you/.profile
$
Выдачи нет, файлы совпадают
$ echo $?
0
0 означает успех, файлы идентичны
$ cmp /usr/you/.profile /usr/mary/.profile
/usr/you/.profile /usr/mary/.profile differ: char 6, line 3
$ echo $?
1
He нуль означает, что файлы различны
$
У некоторых команд, таких, как cmp
и grep
, есть флаг -s
, который заставляет их завершить выполнение с определенным кодом, но подавляет вывод. Оператор if
языка shell
запускает команды в зависимости от кода завершения некоторой команды, а именно:
if команда
then
команды, если условие верно
else
команды, если условие ложно
fi
Местоположение символов перевода строк очень важно: fi
, then
и else
распознаются только после символа перевода строки или точки с запятой.
Оператор if
всегда запускает команду (условие), тогда как в операторе case
сопоставление с шаблоном производится самим интерпретатором. В некоторых версиях UNIX, включая System V, test
является встроенной командой интерпретатора, поэтому if
и test
будут выполняться так же быстро, как и case
. Если test
— не встроенная команда, то операторы case
более эффективны, чем операторы if
, и следует использовать именно их для поиска шаблонов;
$ case "$1" in
hello) command
esac
выполняется быстрее, чем
if test "$1"==hello
Медленнее, если test не встроенная
then
command
fi
Это одна из причин, по которой в языке shell
иногда для проверки условий применяются операторы case
, хотя в большинстве языков программирования использовались бы операторы if
. С другой стороны, с помощью оператора case
непросто определить, имеется ли право доступа к файлу на чтение; здесь предпочтение следует отдать команде test
и оператору if
.
Итак, теперь мы готовы воспользоваться первой версией команды which
, которая выведет сообщение о том, какой файл соответствует команде:
$ cat which
# which cmd: which cmd in PATH is executed, version 1
case $# in
0) echo 'Usage: which command' 1>&2; exit 2
esac
for i in `echo $PATH | sed 's/^:/.:/
s/::/:.:/g
s/:$/:./
s/:/ /g'`
do
if test -f $i/$1 # use test -x if you can
then
echo $i/$1
exit 0 # found it
fi
done
exit 1 # not found
$
Проверим ее:
$ cx which
Сделаем ее выполняемой
$ which which
./which
$ which ed
/bin/ed
$ mv which /usr/you/bin
$ which which
/usr/you/bin/which
$
Первый оператор case
осуществляет контроль ошибки. Обратите внимание на переключение 1>&2
в команде echo
, которое выполняется для того, чтобы сообщение об ошибке не пропало в программном канале. Встроенная команда интерпретатора exit
может использоваться для передачи кода завершения. В нашем примере exit 2
передает код завершения в ситуации, когда команда не выполняется, exit 1
— в ситуации, когда файл не удалось найти, и exit 0
— в ситуации, когда файл найден. Если нет явного оператора exit
, кодом завершения командного файла является код завершения последней выполняемой команды.
Что произойдет, если в вашем текущем каталоге есть программа под именем test
? (Мы предполагаем, что test
не является встроенной командой.)
$ echo 'echo hello' >test
Сделаем поддельную команду test
Читать дальше
Конец ознакомительного отрывка
Купить книгу