строке 10. Этой переменной нам необходимо присвоить значение, которое
включает в себя пару кавычек, поскольку кавычки должны быть частью
строки поиска, которая в конце концов используется оператором find.
Однако обнаружение второй кавычки обычно ЗАВЕРШАЕТ оператор присваива-
ния, а мы этого в данном случае не хотим. Выходом из ситуации является
использование символа \, который отменяет специальное значение следую-
щего за ним символа. В данном случае специальное значение было бы кон-
цом строки присваивания.
Таким образом, кавычка перед звездочкой (*) в строке 10 рассмат-
ривается как часть значения переменной OPT, вместо того, чтобы завер-
шать операцию присваивания. Следующая встреченная кавычка также должна
быть сохранена в значении переменной, чтобы указать конец хранимой
здесь строки поиска, поэтому она также экранирована символом \.
Последняя кавычка в этой строке не экранирована обратной косой чертой.
Эта кавычка соответствует своей обычной функции в смысле интерпретато-
ра shell и завершает оператор присваивания.
Вам нужно поэкспериментировать с использованием кавычек, чтобы
понять его. Когда какой-то командный файл не желает работать правиль-
но, но ошибок не видно, проверьте правильность использования кавычек.
Оставшаяся часть командного файла - это оператор case (строки
21-37), который имеет дело с числом аргументов командной строки. Если
нет никаких аргументов, печатается сообщение об ошибке и мы выходим из
программы. Мы ведь не можем делать никакого поиска командой grep, если
мы даже не знаем, какую строку нужно искать.
Если указан только один аргумент, то это должна быть строка по-
иска. Это также означает, что в командной строке не указаны имена фай-
лов и поэтому мы читаем их со стандартного устройства ввода, т.е. ко-
мандный файл действует как фильтр. Цикл while (строки 26-29) читает со
стандартного ввода имя каждого файла для поиска в нем командой grep
нужной строки. Опция -y команды grep означает нечувствительность к ре-
гистру символов при поиске. Использование этой опции дает нам хорошие
шансы попасть на нужную строку.
Другой интересной особенностью этого цикла являются две команды
grep в строках 28 и 34. Мы ищем нужную строку не только в файле, но
также в каталоге /dev/null. Это кажется странным? Да. Проблема заклю-
чается в самой команде grep. Grep знает, когда в командной строке ука-
зано более одного файла. Если имеется более одного файла, то имя файла
выводится на экран до вывода найденной строки. Если же в командной
строке указан только один файл, то его имя не выводится, поскольку
считается, что пользователь должен помнить это имя. Это создает проб-
лемы при написании командных файлов, когда вы имеете много имен фай-
лов, но они обрабатываются по одному. Мы обрабатываем файлы по одному,
поскольку если бы мы использовали указание группового имени файлов с
помощью метасимволов, то могло бы оказаться слишком много имен файлов
в одной командной строке для команды grep. Поэтому вместо использова-
ния некоторой замысловатой схемы для сокращения количества аргументов,
мы избегаем этого путем обработки в цикле каждого файла по очереди.
Поскольку на самом деле мы ищем большое количество разных строк, то мы
хотим видеть имена файлов, в которых они были найдены.
При указании в командной строке grep каталога /dev/null, grep
всегда печатает имя файла до вывода найденной строки в нашем цикле,
поскольку теперь имеется два имени файла в качестве аргументов. Конеч-
но, в /dev/null ничего нельзя найти, поскольку он пуст по определению.
Последний образец в операторе case (строки 31-36) - это ловушка.
Он соответствует любому количеству позиционных параметров сверх одно-
го, что позволяет нам иметь переменное число каталогов в командной
строке.
Даже хотя мы можем указать несколько каталогов в командной стро-
ке, первым аргументом по-прежнему является строка поиска. Не так легко
сказать: "начиная со второго параметра", поэтому мы сохраняем строку
поиска (в переменной STRING - Прим. перев.) и убираем ее командой
shift. Теперь мы можем получить доступ к остальной части командной
строки с помощью выражения $@.
Давайте посмотрим, что происходит, когда мы ссылаемся на перемен-
ную $OPT для получения опций команды find. Допустим, мы вызвали tgrep
с опцией -c. Когда мы присваиваем значение переменной OPT, мы ставим
строку c в виде "*.c" внутри двойных кавычек, поскольку мы не желаем,
чтобы shell раскрывал эту строку (т.е. трактовал ее как имена всех
файлов, соответствующих данному образцу) именно сейчас. Теперь, как
только к переменной $OPT есть обращение в команде find, значением OPT
является *.c, что означает поиск файлов, символьные имена которых
соответствуют *.c. Для отмены символьной интерпретации мы должны
использовать команду eval. Перед выполнением команды find команда eval
заставляет shell повторно анализировать команду в отношении распрост-
ранения значения переменной. На этом проходе выражение "*.c" превраща-
ется в *.c, что разрешает генерацию имен файлов таким образом, чтобы
были просмотрены все эти файлы.
Указывая $@ в команде find, мы можем производить поиск во всех
каталогах сразу. Таким образом, нам нужно вызвать find только один
раз, что позволяет сберечь время центрального процессора. Одной из ин-
тересных проблем, возникших при разработке данного командного файла
было то, что выражение вида $* не работало. В команде find возникала
ошибка сохранения. Даже запуск shell'а в режиме -x (установленный флаг
разрешения выполнения) не разрешил проблему. Изменение синтаксиса, ка-
жется, помогло разобраться с ней. Оказывается, причина в том, что вы-
ражение $* раскрывается в "$1 $2 ...", в то время как выражение $@
превращается в "$1" "$2" (т.е. в отдельные аргументы). Происходило то,
что выражение $* передавало имена нескольких каталогов команде find
как одну строку. Команда find не могла обнаружить файл такого типа,
поэтому прекращала выполнение. Когда же вместо этого было использовано
выражение $@, команда find получила несколько независимых строк с име-
нами. Это вполне подошло команде find, и все заработало. Такие мелкие
детали всегда требуют много времени для изучения!

    ВОЗМОЖНЫЕ ИССЛЕДОВАНИЯ



В чем разница между двумя следующими операторами?

grep "$1" `find "$2" -print`

и

find "$2" -print | while read F
do
grep "$1" $F
done

Они кажутся совершенно похожими, но существует различие в глав-
ном. Первый оператор - это один вызов команды grep. Аргументами явля-
ются множество имен файлов, поставляемых командой find. Если find сге-
нерирует слишком много имен файлов, то выполнение команды завершится.
О том, что сгенерировано слишком много имен файлов, никакого предуп-
реждения не выдается, но большое количество файлов фатально для grep.
Поэтому мы должны рассматривать такой синтаксис как недопустимый в об-
щем случае.
Второй оператор - это цикл. Он работает медленнее и вызывает grep
много раз, что забирает много времени центрального процессора. Однако
положительным моментом является то, что цикл получает данные по конве-
йеру, который фактически не имеет ограничений на число данных, которое
он может иметь. Наша программа никогда неожиданно не прекратит выпол-
нение.

2.1.4. paths - нахождение пути доступа к исполняемым файлам, со
специальными опциями

------------------------------------------------------------
ИМЯ: paths
------------------------------------------------------------

paths Определитель маршрутных имен файлов со специальными
опциями

    НАЗНАЧЕНИЕ



Выводит на экран каталог, в котором располагается файл, выдает
имя файла в длинном формате или ищет файлы с установленным битом поль-
зовательского идентификатора (setuid bit files) в каталогах по указан-
ному маршруту.

    ФОРМАТ ВЫЗОВА



paths [-l] [-s] file [file ...]

    ПРИМЕР ВЫЗОВА



$ paths -l ed ex vi

Выдает в длинном формате имена файлов, которые являются исполняе-
мыми модулями редакторов ed, ex и vi

    ТЕКСТ ПРОГРАММЫ



1 :
2 # @(#) paths v1.0 Path locator with special options Author: Russ Sage
2а Определитель местонахождения файлов со специальными опциями

4 FORMAT="path"

6 for ARG in $@
7 do
8 if [ '`echo $ARG | cut -c1`" = "-" ]
9 then case $ARG in
10 -l) FORMAT="ls"
11 shift;;
12 -s) FORMAT="set"
13 set "1";;
14 *) echo $0: arg error" >&2
15 echo "usage: $0 [-l] [-s] file [file ...]" >&2
16 exit 1;;
17 esac
18 fi
19 done

21 IFS="${IFS}:"

23 for FILE in $@
24 do
25 for DIR in $PATH
26 do
27 case $FORMAT in
28 path) if [ -f $DIR/$FILE ]
29 then echo $DIR/$FILE
30 fi;;
31 ls) if [ -f $DIR/$FILE ]
32 then ls -l $DIR/$FILE
33 fi;;
34 set) echo "\n:::::::::::::::::::"
35 echo "$DIR"
36 echo "::::::::::::::::::::"
37 ls -al $DIR | grep "^[^ ]*s[^ ]*";;
38 esac
39 done
40 done

    ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ



ARG Содержит каждый аргумент командной строки
DIR Элемент с именем каталога в переменной PATH
FILE Содержит имя каждого файла в командной строке
FORMAT Тип требуемого формата выходных данных
IFS Переменная shell'а, разделитель полей
PATH Переменная shell'а, пути к каталогам исполняемых
модулей

ОПИСАНИЕ

ЗАЧЕМ НАМ НУЖЕН КОМАНДНЫЙ ФАЙЛ paths?

В нашей среде интерпретатора shell переменная с именем PATH со-
держит имена каталогов, отделенные друг от друга символами двоеточия
(:). Каждый раз, когда вы вводите команду после приглашения 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, печатаются оформление из двоеточий и имя
каталога. Это делает распечатку приятной, информативной и наглядной.
Ключевой командой является комбинация ls-grep. Каждое имя файла в
каталоге распечатывается в длинном формате, затем просматривается бит
установки пользовательского идентификатора. Модель такова, что команда
ls -al $DIR печатает следующее:

-------------------------------
|
| -rws--x--x 1 root bin 16235 Sep 13 1985 /bin/su
|
|

Аргумент "^[^ ]*s[^ ]*" означает поиск от начала строки символа,
отличного от пробела, за которым следует один или более символов, от-
личных от пробела, затем символ s и затем один или более символов, от-
личных от пробела. Это выражение ограничивает поиск битами прав досту-
па в начале строки. Если имеется символ s где-либо в правах доступа
(либо в пользовательском идентификаторе процесса, либо в групповом
идентификаторе процесса), то команда grep отрабатывает успешно и печа-
тается вся строка.
Такой вид поиска установленного пользовательского идентификатора
несколько "легковесен" в том смысле, что поиск ведется только согласно
переменной PATH, которая у вас есть. Файлы с установленным пользова-
тельским идентификатором могут находиться в каталогах, которые не ука-
заны в PATH. Однако в такой реализации данная опция обеспечивает быст-
рое обращение к вашим локальным файлам с установленным пользова-
тельским идентификатором.

    ВОЗМОЖНЫЕ МОДИФИКАЦИИ



Данный командный файл открыт для многих различных видов модифика-
ции. Поиск полного имени файла является фундаментальной задачей прог-
раммного обеспечения по сопровождению файлов. Эта возможность позволя-
ет нам полагаться на саму программу paths или использовать paths в ка-
честве куска более объемной программы.
При разработке ваших собственных программ следует обратить внима-
ние на гибкость командного файла paths, которая выражается в отличии
между обрабатываемыми форматами. Первые два формата используют отдель-
ные файлы, а формат set использует каталоги. Дальнейшие дополнения к
командному файлу paths могут касаться любой из этих строк или могут
комбинировать их. Если есть необходимость, программное обеспечение мо-
жет приспособиться к этому.

    2.2. ВЫВОД ИНФОРМАЦИИ


2.2.1. lc - вывод файловой информации на экран по столбцам

-------------------------------------------------------------
ИМЯ: lc
------------------------------------------------------------

lc Выдает список файлов в колоночном формате


    НАЗНАЧЕНИЕ



Выдает информацию о файлах в формате колонок, показывая каталоги
и исполняемые модули. Этот листинг можно пропустить через команду
more.

    ФОРМАТ ВЫЗОВА



lc [-m] [ls options] file [file ...]

    ПРИМЕР ВЫЗОВА



lc -R $HOME

Выдает список всех файлов во всех подкаталогах моего регистра-
ционного каталога.

    ТЕКСТ ПРОГРАММЫ



1 :
2 # @(#) lc v1.0 List files in a column Author: Russ Sage
2а Выводит список файлов в колоночном виде

4 if [ "$1" = "-m" ]
5 then MORE="| /usr/bin/more"
6 shift
7 else MORE=""
8 fi

10 eval "/bin/ls -a $@ | /bin/pr -5t" $MORE # pre System V
11 eval /bin/ls -aCF $@ $MORE # System V

    ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ



MORE Содержит программный канал к команде more

ОПИСАНИЕ

ЗАЧЕМ НАМ НУЖЕН КОМАНДНЫЙ ФАЙЛ lc?

В мире компьютеров многие люди изобретают колесо, а другие люди
изобретают его снова. Если первое колесо не того размера или не того
цвета, делается другое колесо. В нашей конкретной ситуации исходным
колесом является команда ls системы UNIX, которая имеет некоторые не-
достатки в своих ранних реализациях. Она выдает хорошую информацию, но
она печатает имена файлов только в одну колонку, что приводит к нера-
циональному расходованию места и затрудняет чтение имен файлов. Поэто-
му мы создаем версию команды ls, которая отображает распечатки в
несколько колонок.
Как видно из предыдущего листинга, lc имеет две формы. Одна пред-
назначена для систем, более ранних, чем System V, а другая - для
System V и последующих версий UNIX. Причина в том, что System V версии
2 имеет новую команду ls, которая делает именно то, что мы хотим.
Система Berkeley также имеет версию команды ls, которая по умолчанию
использует несколько колонок при выводе на терминал. Но для XENIX и
ранних версий System V мы должны делать это сами. Дело в том, что хотя
в вашей версии UNIX, XENIX или чего-либо еще могут отсутствовать ко-
манды, имеющиеся в других версиях, вы обычно можете построить то, что
вам нужно. Это может потребовать определенных усилий, и ваши программы
могут работать не так быстро и не так эффективно, но вы МОЖЕТЕ полу-
чить нужное средство.
Пользователям интерпретаторов csh и последнего sh, имеющего функ-
ции, видимо, лучше бы заменить весь этот сценарий на то, чтобы сделать
lc псевдонимом (alias). Использовать возможность введения псевдонимов,
чтобы присвоить имя любой корректной командной строке UNIX (например,
вызову команды ls с указанными опциями). Это легче, чем писать команд-
ный файл, но ограничивает вас необходимостью работать с уже имеющимися
командами или опциями. Это быстрее, так как не создается никаких до-
полнительных процессов.
При работе со старым интерпретатором sh мы должны пройти через
обычную процедуру изготовления командного файла и размещения его в ка-
талоге bin. С другой стороны, SCO XENIX System V решает эту проблему,
связывая эти же имена (lc, lf, l) с обычной командной ls и используя
вызывающее имя для определения формы распечатки.
Итак, зачастую имеется много альтернатив. Мастера UNIX, сталкива-
ясь с какой-либо проблемой, не борются с ней с помощью Си или команд-