$
Проверим ее:
$ 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
$ cx test
Сделаем ее выполняемой
$ which which
Попробуем which теперь
hello
Неудача!
./which
$
Вывод: требуется больший контроль. Можно запустить команду
which
(если нет команды
test
в текущем каталоге), чтобы определить полное имя для
test
и задать его явно. Но это не лучшее решение, поскольку команда
test
может присутствовать в различных каталогах в разных версиях системы, а команда
which
зависит от
sed
и
echo
, так что необходимо указать и их полные имена. Можно поступить проще — установить значение
PATH
в командном файле так, чтобы поиск команд осуществлялся только в
/bin
и
/usr/bin
. Конечно, это возможно только в команде
which
, причем прежнее значение
PATH
следует сохранить для определения последовательности каталогов при поиске.
$ cat which
# which cmd: which cmd in PATH is executed, final version
opath=$PATH
PATH=/bin:/usr/bin
case $# in
0) echo 'Usage: which command' 1>&2; exit 2
esac
for i in `echo $opath | sed 's/^:/.:/
s/::/:.:/g
s/ :$/:./
s/:/ /g'`
do
if test -f $i/$1 # this is /bin/test
then # or /usr/bin/test only
echo $i/$1
exit 0 # found it
fi
done
exit 1 # not found
$
Теперь команда
which
выполняется даже в том случае, если есть "поддельная" команда
test
(
sed
или
echo
) среди каталогов, входящих в
PATH
.
$ ls -l test
-rwxrwxrwx 1 you 11 Oct 1 06:55 test
Все еще здесь
$ which which
/usr/you/bin/which
$ which test
./test
$ rm test
$ which test
/bin/test
$
В языке
shell
имеются две операции, объединяющие команды
||
и
&&
, использование которых часто более компактно и удобно, чем оператора
if
. Например, операция
||
может заменить некоторые операторы
if
:
test -f имя_файла || echo имя_файла не существует
эквивалентно
if test ! -f имя_файла
! обращает условие
then
echo имя файла не существует
fi
Операция
||
, несмотря на свой вид, не имеет ничего общего с конвейерами — это обычная операция, означающая ИЛИ. Выполняется команда слева от
||
. Если ее код завершения 0 (успех), справа от
||
команда игнорируется. Если команда слева возвращает другое значение (неудача), выполняется команда справа, и значение всего выражения есть код завершения правой команды. Иными словами,
||
представляет собой обычную операцию ИЛИ, которая не выполняет свою правую часть, если левая часть завершилась успешно. Соответственно
&&
есть обычная операция И, выполняющая свою правую часть, только если левая часть завершилась успешно.
Упражнение 5.4
Почему в команде
which
перед выходом из нее не восстанавливается значение
PATH
из
opath
?
Упражнение 5.5
Если в языке
shell
используется
esac
для завершения оператора
case
и
fi
для завершения оператора
if
, почему для завершения оператора
do
применяется
done
?