Читаем UNIX — универсальная среда программирования полностью

 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 осуществляет контроль ошибки. Обратите внимание на переключение 12 в команде 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' 12; 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?

Упражнение 5.6

Введите в команду which флаг , чтобы выводились все файлы из PATH, а не только первый найденный.

Подсказка: match='exit 0'

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже