держит имена каталогов, отделенные друг от друга символами двоеточия
(:). Каждый раз, когда вы вводите команду после приглашения shell'а,
интерпретатор shell, начиная с первого каталога, указанного в перемен-
ной PATH, смотрит, находится ли введенная вами команда в этом катало-
ге. Если да, то команда выполняется. Если нет, то shell идет в следую-
щий каталог, указываемый переменной PATH, и так далее, пока не будут
проверены все каталоги. Если команда все же не будет найдена, то вы
получите следующее сообщение об ошибке:
---------------------------------------------------------------------------
|
| $ whatchamacallit
| sh: whatchamacallit: not found
|
|
Такой поиск команды осуществляется автоматически, но сама система
не сообщает вам, ГДЕ размещена команда. Нам необходима утилита, кото-
рая ищет и выводит на экран маршрут к указанному файлу. Имея такую
утилиту, вы можете использовать кратчайшие пути получения того, что
вам нужно, и выполнять множество различных трюков. Вы можете комбини-
ровать подобную команду с другими командами для создания гораздо более
мощных средств. С маршрутом можно также комбинировать команды more,
ls, file и cd системы UNIX. Возможно, вы обнаружите и другие команды
по мере экспериментирования.
Команда, несколько похожая на ту, которую мы ищем, существует
где-то в мире системы UNIX Systev V. Например, в системе AT&T это ко-
манда where. В системе UNIX Berkeley это команда which (текст на языке
Си-shell'а) или whereis (исполняемая программа). Whereis дает дополни-
тельную информацию, такую как место размещения файлов с исходными
текстами (в каталоге /usr/src). Увидев, как мы создаем нашу собствен-
ную команду поиска маршрута, вы можете модифицировать ее для обеспече-
ния работы с особенностями некоторых других команд и приспособить та-
кие вещи к вашим нуждам.
Прежде чем мы удовлетворим свои прихоти, давайте бегло глянем на
команду path, более простую, чем paths. Вся программа выглядит пример-
но так:
IFS="${IFS}:"
for FILE in $@
do
for DIR in $PATH
do
if [ -f $DIR/$FILE ]
then echo $DIR/$FILE
fi
done
done
Основная идея очень проста. Сперва мы добавляем двоеточие (:) к
разделителю полей. Нам необходимо сохранить значения, принятые по
умолчанию (пробелы, табуляции, символы новой строки), так, чтобы мы
могли все-таки обрабатывать командную строку с пробелами в качестве
символов-разделителей. Символ : дает нам возможность отдельно рассмат-
ривать каждый маршрут, хранимый в переменной PATH.
Вся программа представляет собой два цикла for. Внешний цикл
просматривает имена всех файлов, указанных в командной строке. Внут-
ренний цикл последовательно обходит все каталоги, содержащиеся в пере-
менной PATH. Для каждого файла просматриваются все каталоги с целью
определения, содержит ли этот каталог файл с таким именем. Полное
маршрутное имя представляет собой комбинацию префикса-каталога и имени
файла (называемых именем каталога и базовым именем соответственно).
Встроенная shell-команда test использована для определения того, су-
ществует ли файл в определенном каталоге.
Если ваша переменная PATH выглядит так:
PATH=.:/bin:/usr/bin:/etc/:$HOME/bin
то внутренний цикл выполнит пять итераций в таком порядке: ., /bin,
/usr/bin, /etc и, наконец, $HOME/bin. Если бы запрос имел вид "path
ll" для поиска утилиты, которую мы создадим позже в этой главе, то ре-
зультат мог бы выглядеть так:
---------------------------------------------------------------------------
|
| /usr/bin/ll
| /usr/russ/bin/ll
|
|
Это значит, что команда ll была найдена в двух местах из вашего набора
маршрутов поиска.
ЧТО ДЕЛАЕТ paths?
Теперь, когда мы знаем, как работает более простая команда path,
мы можем по достоинству оценить дополнительные возможности специальной
команды получения маршрута - команды paths. Paths имеет три основные
функции. Она может выполняться как основная команда path, которую мы
уже рассмотрели, и давать полное маршрутное имя исполняемого модуля.
Она может выдавать маршрут файла в длинном формате. Она также может
выдать список всех файлов с установленным пользовательским идентифика-
тором (setuid bit files), которые есть в ваших маршрутных каталогах.
(См. главу 8, где описаны биты setuid.)
Синтаксис вызова немного отличается для разных опций. Для того
чтобы использовать формат выдачи маршрута или формат команды ls, нужна
такая командная строка:
paths [-l] file [file ...]
как, например, в командах "paths ls who date" или "paths -l ll". Для
поиска файлов с установленным пользовательским идентификатором (setuid
files) не нужно указывать имена файлов в командной строке. Вся команда
должна быть такой:
paths -s
Формат setuid и форматы выдачи маршрута являются взаимоисключаю-
щими, поскольку предполагается, что вы хотите узнать от компьютера,
какие и где находятся файлы, а не отгадывать имена файлов.
Если в командной строке находится какая-то другая опция, то в
стандартный вывод выводится сообщение об ошибке и командный файл за-
вершается. Опции устанавливают флаг формата вывода в одно из трех зна-
чений. Весь дальнейший вывод из командного файла управляется выбранным
форматом вывода.
ПРИМЕРЫ
1. $ paths ls more who paths
/bin/ls
/usr/bin/more
/bin/who
/usr/russ/bin/paths
Поиск маршрутов к командам ls, more, who, paths. При выводе ука-
зываются полные абсолютные маршрутные имена. Обратите внимание, что в
конце имени каждого файла печатается символ новой строки, чтобы полу-
чить распечатку, в которой каждое имя файла стоит в отдельной строке.
2. $ more `paths gettydefs termcap paths`
Если ваша переменная PATH содержит каталог /etc, то этот пример
будет работать. Если нет, то первые два файла не будут найдены. Снача-
ла запускается команда paths, и ее вывод помещается на свое место в
командной строке команды more. Когда запускается команда more, она не
знает, что ее аргументы получены от другой команды. После завершения
работы команды paths команда more принимает вид:
more /etc/gettydefs /etc/termcap /usr/russ/bin/paths
с полными маршрутными именами каждого файла. Этот пример показывает,
как можно заставить команду paths выполнять всю работу по поиску и по-
казу файлов, которые вы хотите увидеть.
3. $ ll `paths ll`
В этом примере в длинном формате выводятся файлы с именами ll,
которые найдет path. (Мы представим нашу версию команды ll несколько
позже в этой же главе.) Как и в предыдущем случае, сначала генериру-
ется информация о маршруте, затем она помещается в командную строку, а
затем запускается команда ll.
4. $ m `paths paths`
В данном примере генерируется маршрутное имя самого командного
файла paths и передается программе m, которая использует команду more
для распечатки. (Командный файл m мы также покажем вам позже.)
ПОЯСНЕНИЯ
В строке 4 инициализируется переменная FORMAT, указывая маршрут-
ный тип поиска. Выполняется действие по умолчанию, точно такое же, как
в командном файле path, который мы рассмотрели ранее.
В строках 6-19 все аргументы командной строки проверяются на кор-
ректность. Критерием того, что аргумент есть опция, является дефис в
роли первого символа. Заметим, что здесь не разрешено использование
синтаксиса "-xyz". Это заставляет вас пользоваться синтаксисом "-x -y
-z". Хотя этот момент может показаться несущественным, на самом деле
он важен. Всегда нужно достигать компромисса между быстрой разработкой
командного файла при согласии на недостатки жесткого синтаксиса - и
разрешением гибкого формата за счет дополнительных усилий по кодирова-
нию и отладке и за счет более медленного выполнения. Ваш выбор зависит
от ваших приоритетов, от количества людей, использующих ваше инстру-
ментальное средство, и от того, насколько критична скорость выполне-
ния. Конечно, если скорость критична, вы, вероятно, захотите использо-
вать каким-то образом язык Си. Мы оставляем обработку конкатенирован-
ных опций в качестве упражнения для читателя.
Цикл for проходит по всем позиционным параметрам. Если первым
символом аргумента является "-", то он сверяется со списком допустимых
аргументов с помощью оператора case в строках 9-17. Опция "-l" изменя-
ет переменную формата, после чего убирается из рассмотрения. Это дела-
ется для освобождения этой позиции, чтобы конечным результатом были
просто имена файлов в командной строке.
Опция "-s" также изменяет переменную формата. Однако, вместо то-
го, чтобы убрать опцию из командной строки, она ликвидирует всю ко-
мандную строку и заменяет ее символом "l". Это заставляет цикл for
проходить только одну итерацию, так как в командной строке теперь
только один параметр. Благодаря такому обращению с командной строкой,
нам не нужен другой цикл: мы можем использовать тот же цикл, что и в
определении маршрута, без всяких модификаций. Поскольку после опции s
не ожидается никаких имен файлов, мы больше не хотим рассматривать ко-
мандную строку.
Если использована опция, которая не является ни l, ни s, то этой
опции соответствует звездочка (*) и в стандартный файл ошибок выво-
дится сообщение об ошибке. Затем командный файл завершается.
Мы бы могли просто проверить первый параметр командной строки,
чтобы выяснить, является ли он опцией, и если является, то установить
эту опцию. Поскольку можно использовать только одну опцию за один раз,
мы могли бы предполагать, что в остальной части командной строки были
имена файлов. Тем не менее, этот цикл допускает простое добавление
других опций, которые могли бы действовать в дополнение к одной основ-
ной. Это более предпочтительно, и оно не влияет на производительность.
В строке 21 мы добавляем символ двоеточия (:) к другим символам
разделителя полей. Мы должны именно добавить двоеточие, а не превра-
тить разделитель полей только в двоеточие. Если бы мы сделали послед-
нее, то это запутало бы разбор имен файлов в командной строке.
Основной цикл представлен в строках 23-40. Это двойной цикл for.
Внешний цикл проходит по каждому файлу в командной строке, а внутрен-
ний цикл обрабатывает каждый каталог, указанный в вашей переменной
PATH. Обратите внимание, что внешний цикл идет по именам файлов, а не
по записям каталогов. Если бы мы выбрали второе, то в распечатке нару-
шился бы порядок имен файлов, поскольку поиск шел бы сначала по ката-
логам.
Следовательно, для каждого имени файла и каталога действие за-
висит от требуемого формата. Маршрутный формат печатает полное имя,
листинговый формат выполняет команду ls, а формат set не ищет указан-
ные имена файлов, но проверяет права доступа и ищет файлы с установ-
ленным пользовательским идентификатором.
Обрат ПРИЕМЫ ПРОФЕССИОНАЛЬНОЙ РАБОТЫ В UNIX
аналогами. Опция ls есть дополнение, которое сокращает объем работы
при вызове. Наличие комбинации поиска и команды ls освобождает того,
кто вызывает этот командный файл от необходимости применять команду
подстановки. Старая и новая команды выглядят примерно так:
ll `path ll`
Находит путь к ll, а затем запускает на нем команду ls -l.
paths -l ll
Находит путь и вместо того, чтобы его напечатать,
выполняет команду ls -l применительно к этому пути.
Формат setuid в строке 34 прощается с подходом "один файл за один
раз" и включает каталоговую машину. Поскольку внешний цикл установлен
на одну итерацию, внутренний цикл становится главным. Для каждого ка-
талога, указанного в PATH, печатаются оформление из двоеточий и имя
каталога. Это делает распечатку приятной, информативной и наглядной.