to exit
17 Enter command (1-3,<>): \c"
18 read CMD
20 case $CMD in
21 "") exit;;
22 1) echo "\nLogfile names:"
23 sed -n -e "/more/s/^.*more \(.*\);;$/\1/p" $HOME/bin/log;;
24 2) more $HOME/bin/autobkplog.home;;
25 3) more$HOME/bin/auto2.bkplogm;;
26 *) echo "log: $CMD is not a command";;
27 esac
Переменные среды выполнения
CMD Команда, полученная от пользователя
HOME Ваш регистрационный каталог в системе
Описание
Зачем нам нужен log?
Если вы читали эту главу, ничего не пропуская, вы уже встречались
с программой autobkp. Выводные данные autobkp очень информативны и
должны быть сохранены как часть операции копирования. Это еще более
важно, если у вас имеются программы, запускаемые с помощью cron. Со
временем некоторые из этих программ может начать работать неверно и
разрушить все вами сделанные копии. Единственный способ проследить за
такими вещами - это использовать файлы протокола. Файлы протокола ко-
манды cron содержат некоторую информацию, но файлы протокола программы
autobkp содержат ее гораздо больше.
Проблема возникает, когда вы сталкиваетесь с наличием нескольких
работ для autobkp. Вы можете не захотеть смешивать невзаимосвязанные
копии файлов в одном и том же файле со списком маршрутов, поэтому вы
создаете несколько файлов pathlist, несколько заданий для cron и
несколько файлов протокола. Если вам нужно выполнить пять или десять
подобных работ, каким образом вы проследите за всеми файлами протоко-
лов, запомните их имена и облегчите их просмотр? Все эти проблемы реше-
ны в командном файле log.
Что делает log?
Командный файл log - это управляемая при помощи меню утилита. Меню
позволяет вам видеть текущие имена файлов в файлах протокола, поэтому
вам нет необходимости помнить их. Остальные команды являются входными
точками в файлы протокола, использующими команду more для просмотра.
Когда мы рассматривали командный файл cpiobr, мы видели, как рабо-
тает управляемая при помощи меню программа. Командный файл log несколь-
ко проще в том смысле, что он делает только один проход. Кроме того,
log - это "живая" программа. Она не является статичной и должна посто-
янно изменяться в соответствии с вашими процедурами копирования.
Посредством такой модификации log способна сообщить вам действительные
имена файлов.
Log является разновидностью программы, ссылающейся сама на себя.
Для показа действительных имен файлов она просматривает свое содержимое
и выбирает (используя sed) имена log-файлов из команды more, которая
выводит их. Поскольку вы добавляете файлы протокола, программа log мо-
жет хранить текущие, потому что она просматривает сама себя для опреде-
ления того, что соответствует действительности. Применяя процедуру по-
иска таким образом, мы избавляемся от необходимости сохранять отдельные
файлы данных с именами в них или использовать какие-то соглашения об
именовании выполнения той же задачи. Способность программы log обра-
щаться самой к себе позволяет вам добавлять неограниченное число файлов
протокола в список, и вам предоставляется свобода по выбору имен таких
файлов.
Возможно, вы заметили, что стратегия, использованная в командном
файле log, может быть использована для обеспечения вывода на экран лю-
бого набора файлов (записные книжки, документация или еще что-то). Все,
что вам нужно сделать для этого - записать их в соответствии с командой
more и добавить столько команд в главное меню, сколько вы хотите.
Пояснения
Строка 4 очищает экран, используя команду c, представленную ниже в
этой книге. (Вместо этого вы снова можете использовать команду clear,
если она доступна.)
Строка 5 устанавливает в позиционные параметры выход команды date.
Это то же самое, что мы делали в программе cpiobr. Строки 6-17 выводят
меню. Здесь использован один оператор echo, как описано в cpiobr. Стро-
ка 13 читает команду пользователя.
Строки 20-27 выполняют основную работу программы. Если введенная
команда была просто возвратом каретки (трактуется как нуль), программа
завершается. В строке 23 команда sed просматривает файл $HOME/bin/log.
Это требует, чтобы вы поместили log в подкаталоге двоичных модулей ва-
шего регистрационного каталога. Если вы разместите ее где-либо в другом
месте, вы должны изменить эту строку. Команда sed использует ключ -n,
который запрещает вывод, за исключением того, что явно указано для пе-
чати. Строка -e находит имена файлов.
Данный подход использует функцию замены в команде sed. Таким обра-
зом мы можем заменить все за исключением имени файла, а затем напеча-
тать его. Смысл этой записи примерно такой: сперва мы ищем выражение
more (/more/), находя тем самым все строки в файле протокола, содержа-
щие слово "more". По определению, каждый файл протокола выводится на
экран, используя команду more. Поскольку вы добавляете файлы протокола,
каждая новая строка должна содержать слово more, поэтому файлы нахо-
дятся автоматически по выражению команды sed.
Затем мы указываем команде sed сделать замену. Первое выражение
содержит в себе всю строку от начала до конца, но мы применяем круглые
скобки для отметки внутри нее образца .*, тем самым выделяя часть стро-
ки между пробелом после "more" и первой точкой с запятой в конце стро-
ки. Если вы посмотрите на все строки в файле log, которые начинаются с
"more", то вы увидите, что это соответствует имени файла, которое мы
ищем.
Затем мы указываем команде sed заменить всю строку на первый обра-
зец "pattern 1". "Pattern 1" - это запись команды sed для первого отме-
ченного или "отмеченного биркой" выражения. Другими словами, мы замени-
ли имя файла на всю строку целиком и указали команде sed напечатать ре-
зультат, тем самым выдавая на экран имя файла.
Эта работа выполняется для такого количества операторов more,
сколько вы имеете. Чем больше файлов log вы имеете, тем больше файлов
обрабатывает команда sed. Обратите внимание, что оператор sed просмат-
ривает любое количество символов от начала строки для нахождения слова
"more". Не указывая в программе конкретное число символов, на которое
нужно отступить, вы получаете тем самым свободу выбора ваших собствен-
ных уровней отступа.
Если введенная команда не является допустимой, выдается сообщение
об ошибке.
Эта программа не имеет цикла, поэтому срабатывает один раз. Если
вы хотите запустить ее снова, вы должны снова ввести log.
Пример
$ log
1
После запуска программы выводится меню. Введите число 1 для того,
чтобы увидеть все имена log-файлов.
Теперь, когда мы изучили, как распознавать и управлять файлами во-
обще, давайте рассмотрим некоторые систематические методы управления
ИНФОРМАЦИЕЙ в файлах. Мы начинаем в следующей главе с файлов, которые
важны для нас как для программистов.
* ГЛАВА 2. Доступ к файлам *
СОДЕРЖАНИЕ
Введение
2.1. Поиск файлов
2.1.1. tree - визуализация файлового дерева
2.1.2. thead - печать начала каждого файла
2.1.3. tgrep - поиск строк в дереве файловой системы
2.1.4. paths - нахождение пути доступа к исполняемым файлам, со
специальными опциями
2.2. Вывод информации
2.2.1. lc - вывод файловой информации на экран по столбцам
2.2.2. ll - вывод файловой информации в длинном формате
2.2.3. kind - вывод однотипных файлов
2.2.4. m - простой доступ к команде more
2.2.5. mmm - обработка программой nroff макрокоманд для рукописей
2.2.6. pall - печать всех файлов в дереве
В главе 1 был представлен обзор общей структуры системы UNIX и
показано, как взаимодействуют ее различные части. Это похоже на введе-
ние в географию, когда на глобусе показывают континенты и крупные вод-
ные пространства. Такая информация, хотя и является хорошим фундамен-
том для общих знаний, вряд ли поможет найти наилучший путь из
Сан-Франциско в Лос-Анжелес. Необходим следующий уровень детализации:
названия поселений, дорог, развилок, улиц, адресов.
Файловая система UNIX похожа на континент со множеством городов
и, действительно, с адресами внутри городов. Каталоги и различные
уровни подкаталогов можно сравнить с маршрутами между различными пунк-
тами назначения, названия файлов - с адресами. Большое число путей и
мест назначения может выглядеть пугающе, но благодаря регулярности и
логичности, файловая система UNIX позволяет вам легко перемещаться
из одного места в другое, если вы знаете несколько основополагающих
принципов.
Будучи пользователями UNIX, все мы научились пользоваться основ-
ными командами файловой информации, как, например, ls с различными оп-
циями. Мы знаем, как перемещаться между каталогами и копировать или
перемещать файлы. Тем не менее, находить нужную информацию о файлах из
всей массы информации не так-то легко. Нам необходимо создать инстру-
ментальные средства, которые используют древовидную структуру файлов в
UNIX, чтобы находить то, что мы ищем, и, соответственно, выводить ин-
формацию о файлах на экран, печатать листинги содержимого файлов и
т.д.
Эта глава знакомит с инструментальными средствами, которые облег-
чают задачу поиска и доступа к файлам. Доступ к файлам может быть
обеспечен различными способами, поэтому техника и стиль меняются от
одного командного файла к другому. Например, в некоторых случаях вам
нужно найти имена всех файлов в данном сегменте файлового дерева, в
других случаях вас будут интересовать файлы только заданного типа:
текстовые файлы вообще или исходные файлы на языке Си в частности.
КОМБИНИРОВАНИЕ ПРОДУКТИВНЫХ ИДЕЙ
Две концепции являются общими почти для всех файловых инструмен-
тальных средств. Первая - это идея рекурсивного поиска, которая озна-
чает, что некоторые команды системы UNIX (например, find) просматрива-
ют все файловое дерево, начиная с некоторой заданной начальной точки
(или с текущего каталога). Если в данном каталоге встречается подката-
лог, то его содержимое тоже исследуется - и так далее вниз к самому
нижнему под-подкаталогу. Так проходятся маршруты ко всем файлам в це-
лом дереве.
Стандартные команды системы UNIX обеспечивают только ограниченное
число основных функций, которые могут работать рекурсивно по всему
файловому дереву. Наша стратегия при создании инструментальных средств
в этой главе - воспользоваться преимуществами такого рекурсивного по-
иска и распространить их на многие другие функции.
Вторая ключевая идея, связанная с полезными файловыми инструмен-
тальными средствами - это возможность соединения команд с программными
каналами и управление потоком данных с помощью переадресации. Вероят-
но, вы уже встречались с подобными особенностями в вашей собственной
работе с UNIX и эффективно их использовали. Возможно, вы еще не осоз-
нали, что соединение рекурсивного поиска, предоставляемого некоторыми
стандартными командами, со специфическими функциями, предоставляемыми
другими командами, позволяет нам создать команды, которые автомати-
чески обходят обширные файловые деревья и извлекают нужную информацию.
(В следующей главе мы выйдем за пределы распечатки и отображения ин-
формации на экран и научимся работать с файлами так, что мы сможем ко-
пировать, перемещать и восстанавливать их по мере надобности.)
Для удобства мы сгруппируем инструментальные средства в два раз-
дела: поиск файлов и распечатка файловой информации. Имеет смысл
представлять их в таком порядке, так как вы сначала должны найти файл,
чтобы потом с ним работать.
Этот раздел посвящен поиску файлов, где бы они ни находились, вы-
воду на экран выбранной информации и поиску символьных строк внутри
файлов.
Первая программа, tree, обходит все файловое дерево и печатает
имена всех файлов в формате визуального дерева. Она рекурсивно спуска-
ется в каждый каталог и находит все его файлы, обеспечивая тем самым
глобальный осмотр файловых областей и их вложенной по глубине структу-
ры.
Другое инструментальное средство - это thead. Thead печатает
несколько первых строк текстовых файлов, которые находятся в данном
сегменте файлового дерева. Просматривая заголовок, т.е. первые
несколько строк файла, вы можете получить достаточно информации, чтобы
идентифицировать содержимое файла. При вызове thead вы можете явно за-
дать каталог либо передать команде thead по конвейеру список полных
имен файлов. Это делает команду thead фильтром - особым видом команд
системы UNIX, который мы обсудим позже.
Следующее инструментальное средство - tgrep. Как следует из наз-
вания, это еще одна команда, связанная с файловым деревом, которая
использует утилиту grep. Tgrep ищет символьные строки в каждом файле,
который находится в данном сегменте файлового дерева. Tgrep также яв-
ляется фильтром, так что имена файлов можно передавать ей по конвейе-
ру.
В нашем последнем проекте в этом разделе мы обратимся к использо-
ванию каталогов как средства "навигации". Сначала мы опишем основной
алгоритм для утилиты, которая для каждого файла из заданного списка
файлов проверяет, находится ли этот файл в каком-либо каталоге по ука-
занному маршруту поиска. Затем мы построим paths - утилиту, которая
дополняет функцию поиска полезными опциями.
РАСПЕЧАТКА ФАЙЛОВОЙ ИНФОРМАЦИИ
Этот раздел знакомит вас с инструментальными средствами, предназ-
наченными для вывода на экран имен файлов и их содержимого. Инструмен-
ты такого рода весьма полезны, так как они могут значительно уменьшить
количество необходимых символов, набираемых с клавиатуры при запуске
команды, и внести больше смысла в одну команду.
Первые два командных файла являются пре- и постпроцессорами для
команды ls. Команда lc выводит файловую информацию по столбцам, коман-
да ll перечисляет файлы в длинном формате. Эти командные файлы допол-
нены опциями команды ls, чтобы сделать распечатки более информативны-
ми. Так как команда ls используется довольно часто, упаковка наиболее
часто применяемых нажатий клавиш в командные файлы представляется це-
лесообразной. Упаковка уменьшает количество постоянно набираемых сим-
волов и упрощает использование команд, исключает необходимость запоми-
нания подробного синтаксиса.
Третье инструментальное средство - это kind. Kind - еще один ко-
мандный файл препроцессорного типа, использующий команду UNIX file.
Команда file читает указанный файл и затем сообщает, является ли этот
файл текстовым, архивным или исполняемым. Поскольку распечатки команды
file не выбирают файлы заданного типа, возникает необходимость в соз-
дании для этого специальной утилиты. Команда kind работает с распечат-
кой команды file. Kind выводит на экран имена файлов только заданного
типа.
Еще один командный файл - m, который облегчает работу со стан-
дартной командой more системы UNIX, уменьшая количество необходимых
для запуска команды символов и упрощая интерфейс. Делается это без по-
тери гибкости: так же, как вы можете использовать команду more для
файла или передать команде more данные по программному каналу, вы мо-
жете сделать то же самое для m.
Следующий командный файл - это mmm. Он состоит из одной заготов-
ленной командной строки для программы nroff системы UNIX. Существует
много способов вызова команды nroff и множество различных опций к ней.
Если же вы редко используете nroff, у вас могут возникнуть трудности в
запоминании специфических опций, необходимых для вашей работы с коман-
дой. Эти проблемы отпадут, если у вас есть команда mmm. Определите оп-
ции, которые вы обычно используете, и введите их в командный файл mmm
(о том, как это сделать практически, речь пойдет ниже). Теперь доста-
точно набрать mmm - и вы имеете возможность работать с вашей командой
nroff.
Последняя утилита - pall. Pall обходит файловое дерево, ведя по-
иск файлов заданного типа, и готовит их к выводу на принтер. Команда
pr системы UNIX используется для разбивки на страницы всех файлов
вместе и включения заголовков. Эта команда предлагает на рассмотрение
принтеру один большой файл и наиболее полезна в тех случаях, когда у
вас имеется множество каталогов с текстовыми файлами или с исходными
файлами программ.
Определив в общем основные наши задачи, перейдем к более близкому
знакомству с упомянутыми инструментальными средствами.
2.1.1. tree - визуализация файлового дерева
ИМЯ: TREE
tree - вывод на экран структуры файлового дерева
Находит все файлы в файловом дереве и выводит на экран имена фай-
лов, показывая иерархическую структуру файлового дерева.
tree [dir]
$ tree $HOME
Выводит структуру файлового дерева регистрационного каталога.
1 :
2 # @(#) tree v1.0 Visual display of a file tree Author: Russ Sage
2а вывод на экран структуры файлового дерева
4 if [ "$#" -gt 1 ]
5 then echo "tree: wrong arg count">&2
6 echo "usage: tree [dir]" >&2
7 exit 2
8 fi
9 if [ "$#" -eq 1 ]
10 then if [ ! -d $1 ]
11 then echo "$0: $1 not a directory">&2
12 echo "usage: tree [dir]" >&2
13 exit 2
14 fi
15 fi
17 find ${1:-.} -print | sort | sed -e "1p" -e "1d" \
18 -e "s|[^/]*/| /|g" \
19 -e "s|[^ */|/|" \
20 -e "s|/\([^/]*\)$|\1|"
ОПИСАНИЕ
ЗАЧЕМ НАМ НУЖЕН КОМАНДНЫЙ ФАЙЛ tree?
Как мы уже отмечали, вся система UNIX строится вокруг файловой
системы, которая похожа на дерево. Дерево, с которым мы работаем в
системе UNIX, растет вверх ногами: корень находится вверху, а ветви и
листва растут вниз от корня. Физическая структура реальных деревьев и
файловых деревьев, используемых в системе UNIX, очень сходна: один ко-
рень (начальная точка) и один ствол. Как глубоко и как далеко могут
уходить ветви от основного ствола - не ограничивается ничем, кроме ог-
раничений физического пространства. Аналогично, число листьев, которые
может иметь каждая ветвь, фактически не ограничено.
Многое в системе UNIX задумано для того, чтобы приспособиться к
дереву. Некоторые команды обходят дерево и сообщают о его компонентах,
но обычно их сообщения выдаются в форме, не очень удобной для чтения
человеком. Это делает командные файлы весьма мощными инструментами.
Перевести необработанные, недружественные сообщения командных файлов в
удобный, информативный вид довольно легко.
Команда tree является комбинацией команд системы UNIX, которые
представляют логическую файловую структуру в наглядной форме. Эта ко-
манда полезна для получения глобальной картины файлов, их расположения
в иерархической структуре файлового дерева, гнездовой структуры ката-
логов и подкаталогов.
ЧТО ДЕЛАЕТ tree?
Команда tree - это постпроцессор для команды UNIX find. Find
просматривает сегмент файлового дерева и полные имена всех файлов, ко-
торые соответствуют заданному критерию. Команда tree использует утили-
ту sed системы UNIX, чтобы перевести выход команды find в наглядную
форму.
Входным параметром для команды tree является имя каталога, кото-
рое может быть указано в любом абсолютном виде, например,
/usr/spool/uucp, или в относительном, например, ../../bin. Если ника-
кого имени не указано, подразумевается ., что является текущим катало-
гом.
Имя каталога является началом (или корнем) отображаемого дерева.
Чтобы показать глубину дерева, все файлы, подчиненные данному катало-
гу, отображаются с отступом. Для удобства представления гнездовой
структуры, между следующими друг за другом ответвлениями печатается
косая черта (/).
Рассмотрим пример структуры каталога. Пусть корневым каталогом
будет /tmp с двумя каталогами: a и b. В каталоге a находится подката-
лог aa, который содержит файл file1, а в каталоге b , соответственно,
подкаталог bb, содержащий файл file2. Команда find выдаст распечатку
такого вида:
# find /tmp -print
/tmp
/tmp/a
/tmp/a/aa
/tmp/a/aa/file1
/tmp/b
/tmp/b/bb
/tmp/b/bb/file2
Как видно из этого листинга, файлы a и aa есть каталоги, а файл
file1 находится внизу файлового дерева. Сравните этот результат с ре-
зультатом, который выдает команда tree, используя утилиту sed.
# tree /tmp
/tmp
/ a
/ / aa
/ / / file1
/ b
/ / bb
/ / / file2
Корневым каталогом в этом листинге является каталог /tmp. Там,
где дерево переходит на более глубокий уровень, печатаются только сим-
волы косой черты. Первый уровень - /tmp, под этим уровнем находятся
файлы-каталоги a и b, затем, соответственно, их подкаталоги aa и bb.
Исходя из этого листинга, мы делаем вывод, что на первом уровне ката-
лога находятся два файла (и эти файлы в действительности являются ка-
талогами) и что два файла находятся в подчиненных каталогах. Отметим,
что мы смогли идентифицировать aa и bb как каталоги только потому, что
в них присутствуют файлы file1 и file2.
Сравните этот листинг с выходом "необработанной" команды find.
Выход команды tree исключает отвлекающее внимание повторение элементов
путей доступа при каждом переходе к более низкому уровню. Благодаря
этому, сразу же видно СУЩЕСТВЕННУЮ информацию. Вот что мы имеем в ви-
ду, когда говорим о создании более наглядного для человека интерфейса
с системой UNIX.
1. $ tree
Использует подразумеваемый каталог (текущий каталог, что рав-
носильно команде "$ tree .") в качестве начала файлового дерева.
2. $ tree /
Печатает древовидный листинг для КАЖДОГО файла всей системы. Ко-
манда find при таком ее запуске начинает с корневого каталога и выдает
информацию о всех файлах системы.
3. $ tree $HOME/..
Показывает древовидный формат для всех других пользователей
системы (предполагается, что все пользовательские каталоги находятся в
одном и том же каталоге, например /usr/*).
Первая строка содержит только знак двоеточия (:) - "нулевую ко-
манду". Это связано с тем, что все командные файлы, описываемые в этой
книге, сделаны так, чтобы их можно было запускать в среде интерпрета-
тора Bourne shell. Наш комментарий в строке 2, идентифицирующий
версию, начинается со знака решетки (#). Си-shell ищет этот знак как
первый знак командного файла. Если он найден, то предпринимается по-
пытка выполнить данный командный файл. В противном случае Си-shell пе-
редает командный файл интерпретатору Bourne shell. Вот почему мы не
хотим начинать первую строку со знака #. Мы, конечно, могли бы оста-
вить первую строку чистой, но чистая строка невидима и может быть слу-
чайно удалена. Соответственно мы будем использовать чистые строки в
других случаях, чтобы выделить важные участки программы.
Строка 2 идентифицирует версию. Символьная строка @(#) есть спе-
циальная последовательность в строке комментария, которая распознается
как строка "what" ("что"). Команда what в системе UNIX читает файл и
печатает сообщение, которое следует за строкой "what". Чтобы идентифи-
цировать версию данного командного файла, наберите
# what tree
и будет напечатано следующее сообщение:
tree:
tree v1.0 Visual display of a file tree Author: Russ Sage
Строки 4-7 проверяют, не слишком ли много аргументов было переда-
но командной строке. Это осуществляется путем исследования переменной
$#, которая представляет собой счетчик числа позиционных параметров
командной строки. Если насчитывается более одного параметра, печата-
ется соответствующее сообщение об ошибке в стандартный файл ошибок
(stderr) и программа останавливается с плохим значением статуса.
Отметим, что команда echo обычно печатает в стандартный выход
(stdout). Мы можем перенаправить stdout в другой файловый дескриптор,
указав его. В данном случае мы собираемся печатать в stderr. Синтаксис
переводится так: "вывести эту строку и перенаправить ее в файловый
дескриптор (&) стандартного файла ошибок (2)". Печать сообщений об
ошибках в stderr обеспечивает согласованное поведение командного файла
независимо от среды, в которой он запущен.
Отметим также, что коды статуса выхода в интерпретаторе shell
противоположны тем, которые используются при программировании на языке
Си. В Си истинное значение есть 1, ложное отлично от 1. При программи-
ровании на языке shell успешным статусом выхода (истиной) является 0,
а плохим статусом (ложью) ненулевое значение.
Вы, возможно, удивитесь, почему мы так беспокоимся о том, чтобы
вернуть ложный статус выхода, если командный файл собирается просто
напечатать сообщение об ошибке и прекратить работу. Дело в том, что
все инструментальные средства системы UNIX должны быть спроектированы
так, чтобы они могли быть связаны с другими командами и процессами, в
которые они могут быть встроены. Возможно, что другой команде необхо-
димо будет вызвать команду tree и проверить, корректно ли она отрабо-
тала. Хорошим стилем проектирования программных средств является прог-
нозирование и разрешение многих способов использования программы.
Строки 9-15 проверяют, чтобы любые параметры, передаваемые ко-
мандной строке, были действительно каталогами, как указано в нашем
синтаксисе. Напомним, что в командной строке может быть помещен только
один каталог. Если мы используем только один параметр и этот параметр
не является каталогом, то мы печатаем сообщение об ошибке и выходим.
Таким образом, операторы проверки гарантируют, что либо не использу-
ется ни один параметр, либо единственный используемый параметр явля-
ется корректным каталогом.
Мы подошли к сердцу команды tree - это строки 17-20. Главным
здесь является команда find системы UNIX. Каталог, в котором ведется
поиск, определяется при запуске команды. Синтаксис ${1:-.} является
формой параметрической подстановки и означает следующее: если $1 (что
является первым позиционным параметром) установлен (иными словами,
если аргумент был передан командной строке и был ненулевым), то нужно
использовать это значение. В противном случае следует использовать ка-
талог . (текущий каталог). Этот тип подстановки дает нам возможность
запускать команду tree без указания имени каталога (когда после tree
на командной строке ничего не следует),- то есть работать в режиме "по
умолчанию", что часто используется в различных файловых инструментах.
Команда find выводит на печать полное имя каждого файла, который
ей встречается. Поскольку не используется никакая специальная опция
для селекции файлов, печатаются все имена. После этого все полные име-
на файлов сортируются для более удобного чтения. Такая сортировка
несколько увеличивает время работы команды, однако наглядность резуль-
тата говорит о том, что это время было потрачено с пользой.
Далее, отсортированные полные имена файлов передаются по прог-
раммному каналу команде sed системы Unix. Sed - это "потоковый редак-
тор", очень гибкое средство, которое может быть использовано для иден-
тификации и обработки различных образцов текста. Опции -e являются
операциями редактирования, применяемыми к поступающим данным. Первый
оператор просто сообщает команде sed, что нужно напечатать первую
строку, затем удалить строку 1. Это делается для того, чтобы напеча-
тать название корневого каталога, который исследуется. Этой строке не
требуется никакой дальнейшей модификации, так как корневой каталог не
имеет никаких дополнительных элементов путей доступа, которые нужно
было бы трансформировать в символы косой черты для показа отступов.
Удаление первой строки связано с тем, что она не нужна в дальнейшей
работе.
Вторая операция редактирования является командой подстановки. Она
заменяет каждый символ, отличный от символа косой черты (вплоть до
первого символа /) на последовательность пробелов и затем один символ
(/). Это избавляет нас от печатания имен промежуточных каталогов впе-
реди полного имени файла. Буква g в конце этой строки означает, что
эта операция выполняется глобально, то есть для всех считываемых сим-
волов. Итак, теперь строка состоит из начального элемента пути и одной
или более последовательностей пробелов, разделенных символами косой
черты. Символы обратной косой черты (\) в конце операций редактирова-
ния - это символы продолжения, которые сообщают команде sed, что нужно
продолжить работу со следующей строкой в текущем пакете операций ре-
дактирования.
Третья операция редактирования (строка 19) также является коман-
дой подстановки и заменяет каждый символ, который не является пробелом
(вплоть до символа /) на "не символ" и один символ косой черты. Этот
оператор удаляет пробелы из предыдущего результата редактирования и
смещает символ в самую левую позицию. Это создает гнездовую индикацию,
которую мы видели в предыдущем примере.
Последняя операция редактирования (в строке 20) заменяет символ
косой черты и все отличные от него символы (до конца строки) просто на
символы, отличные от /. Отметим, что это устраняет самый правый символ
/, который присутствует в листинге команды find. В результате остается
имя подчиненного файла, сдвинутое вправо.
Отметим синтаксис \1 команды sed - признак, относящийся к первому
(в данном случае единственному) регулярному выражению в скобках, кото-
рое ему предшествует. В данном случае команде sed указано пройти сим-
волы, соответствующие регулярному выражению - символы, отличные от /.
2.1.2. thead - печать начала каждого файла
ИМЯ: thead
thеаd Печатает заголовок (первые несколько строк) файлов.
Пройти файловое дерево и напечатать первые несколько строк каждо-
го файла. Если не указан каталог, то thead действует как фильтр.
thead [dir...]
$ find $HOME/src -name "*.c" -print | sort | thead
Печатает заголовки (первые несколько строк) всех моих исходных
файлов на языке Си.
1 :
2 # @(#) thead v1.0 Prints head of files in tree Author: Russ Sage
2а Печатает заголовки файлов в дереве
4 if [ "`echo $1|cut -c1`" = "-" ]
5 then echo "$0: arg error"
6 echo "usage: $0 [dir ...]"
7 exit 1
8 fi
10 case $# in
11 0) while read FILE
12 do
13 if file $FILE | fgrep text >/dev/null 2>&1
14 then echo "\n:::::::::::::::::::::"
15 echo " $FILE"
16 echo "\n:::::::::::::::::::::"
17 head -15 $FILE
18 fi
19 done;;
20 *) for NAME in $*
21 do
22 find $NAME -type f -print | sort | wile read FILE
23 do
24 if file $FILE | fgrep text >/dev/null 2>&1
25 then echo "\n:::::::::::::::::::::"
26 echo " $FILE"
27 echo "\n:::::::::::::::::::::"
28 head -15 $FILE
29 fi
30 done
31 done;;
32 esac
ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ
FILE Содержит имя каждого файла
NAME Имя каталога, заданное в командной строке
ОПИСАНИЕ
ЗАЧЕМ НУЖЕН КОМАНДНЫЙ ФАЙЛ thead?
Как уже объяснялось ранее в этой главе, иерархическая файловая
система является очень значительной частью системы UNIX. Однако, толь-
ко несколько команд в UNIX имеют дело непосредственно с рекурсивным
поиском файлов. Единственный способ расширить возможности системы -
создать новые рекурсивные утилиты, работающие с файлами. В данном слу-
чае мы соединим нашу стратегию поиска по дереву с командой head систе-
мы UNIX для упрощения идентификации содержимого всех файлов в выделен-
ном сегменте файлового дерева.
Иногда у нас, возможно, будет возникать желание просмотреть файлы
в более чем одном каталоге. В больших проектах разработки программного
обеспечения файлы обычно создаются в нескольких иерархических катало-
гах. Thead может работать со множеством путей доступа и выводить заго-
ловки (несколько первых строк файлов) в виде непрерывного потока.
ЧТО ДЕЛАЕТ thead?
Thead - это препроцессорная команда к команде head системы UNIX.
Команда head очень примитивна, но, добавляя к ней управляющую структу-
ру и логику, мы можем создать очень полезное инструментальное
средство, которого нет в стандартной среде UNIX.
Например, мы захотели просмотреть заголовки всех текстовых файлов
в нашем регистрационном каталоге. Если у нас имеется большое число
подкаталогов, нам необходимо все их пройти и просмотреть все файлы,
содержащиеся в них. Мы можем сделать это с помощью команды
$ thead $HOME
Если мы хотим просмотреть только исходные файлы на языке Си
(*.c), то представленный выше синтаксис не годится для этого. Он не
обладает достаточной гибкостью. Нам необходимо иметь способ указать
(или квалифицировать) файлы в $HOME перед тем, как просматривать их.
Так как команда thead может воспринимать полные имена файлов, мы можем
использовать следующую команду:
$ find $HOME -name "*.c" -print | sort | thead
Команда find генерирует список файлов с расширением C, который
сортируется и подается по каналу на вход команде thead.
Как видно из представленных двух примеров, весьма полезной для
командного файла является возможность получать входные данные либо из
аргументов командной строки (как в первом примере), либо по программ-
ному каналу (как во втором примере). Способность использовать прог-
раммный канал позволяет вам применять какие-либо другие команды систе-
мы UNIX, которые могут отбирать входные данные для вашего командного
файла. Команда с такой двойной возможностью называется ФИЛЬТРОМ. Среди
стандартных команд системы UNIX вы найдете лишь несколько команд-филь-
тров, таких как wc, awk, sort.
Эти два способа поступления входных данных в программы делают ин-
терфейс с командными файлами очень гибким. Мы можем подстраивать прог-
рамные средства под наши нужды, а не подстраивать наши желания под
имеющееся программное обеспечение.
Аргументами для команды thead являются каталоги. Никаких опций,
начинающихся со знака "-" нет, только каталог или полные имена файлов.
Команда thead знает из синтаксиса, какой способ запуска команды будет
использоваться. Если командная строка содержит имя файла, thead
просмотрит все позиционные параметры. Если никакие имена не указаны,
thead читает стандартный ввод (stdin) и останавливается, когда встре-
чает EOF. (Такое бывает в случае, когда команда thead получает входные
из программного канала.)
Для каждого файла, с которым работает thead, выполняется контроль
- текстовый ли это файл. Применение команды head к исполняемым модулям
приводит к выводу "таинственных" символов на экран и иногда может выз-
вать дамп оперативной памяти.
1. $ thead /etc
Печатает данные из каждого текстового файла, находящегося в ката-
логе /etc. Очень полезная команда, так как большинство файлов в /etc
являются исполняемыми модулями. Удобно иметь возможность быстро изоли-
ровать текстовые файлы.
2. $ thead /usr/include
Просматривает все подключаемые файлы (*.h), даже в системном под-
каталоге sys.
3. $ find $HOME -ctime 0 -print | thead
Ищет все файлы в вашем регистрационном каталоге, которые были из-
менены в течении последних 24 часов. Для каждого файла проверяется,
текстовый ли он. Если файл текстовый, то он печатается.
Строки 4-8 выполняют проверку ошибок. Так как команда thead не
имеет никаких опций, любые позиционные параметры, которые начинаются с
дефиса (-) являются неверными. Если первым символом первого позицион-
ного параметра оказывается "-", то печатается сообщение "argument
error" (ошибка аргумента) вместе с сообщением о способе запуска и ко-
манда thead прекращает работу.
Некоторые приемы программирования для интерпретатора shell,
используемые в этих строках, довольно часто встречаются в данной кни-
ге, поэтому имеет смысл остановиться на них подробнее.
Проанализируем строку 4, работающую изнутри наружу. Команда echo
выдает содержимое $1 (текущий параметр командной строки), которое пе-
редается по программному каналу команде cut. Команда cut используется
для того, чтобы выделить определенные символы или группы символов из
строки. В данном случае опция -c1 используется для получения только
первого символа.
КОМАНДА cut ДЛЯ BSD
В системе BSD нет команды cut, но следующий командный файл все же
"вырезает" первое непустое поле в текущем аргументе.
Предположим, мы используем команду для генерации целого набора
строк. В данном случае это команда who:
for NAME in 'who | sed "s/^\([^ ]*\).*/\1/"'
do
done
Для каждой обнаруженной строки (аргумента) команда sed должна
подставить вторую строку символов вместо первой строки. Первая строка
- это строка, которая вырезается. Мы ищем от начала строки (^) символ,
отличный от пробела ([^ ]), за которым следует любое число непустых
символов (*). Эта операция прерывается по достижении пробела. Набор
непустых символов ограничивается обратными косыми чертами \( и \).
Впоследствии ссылка на этот набор дается в виде \1. Символы .* означа-
ют, что после того, как найден пробел, необходимо считать подходящими
все символы до конца строки. Мы находимся фактически сразу после того,
что заключено в пару символов \( и \). Группируя первый набор симво-
лов, отличных от пробела, мы получаем то, что является результатом ра-
боты команды "cut -f1".
В этом месте мы подходим к знакам ударения (`), окаймляющим все
выражение. Они берут результат работы всех команд, заключенных в знаки
ударения и передают на следующую охватывающую структуру в наших вло-
женных выражениях. Этот следующий уровень окаймления указан кавычками.
Кавычки превращают символ в строку, чтобы его можно было сравнить с
символом "-". Следующий слой - квадратные скобки, указывающие условие
для оператора if. Это приводит к тому, что генерируется нулевое (исти-
на) или ненулевое (ложь) условие, которое управляет тем, будет ли вы-
полнена часть then оператора if-then.
Мы не собираемся подробно анализировать много строк данного ко-
мандного файла, но мы хотим показать вам, как читать выражение или всю
строку текста программы так, чтобы это имело смысл.
Остальная часть командного файла представляет собой один огромный
оператор выбора (case). Аргументом, используемым для ветвления, явля-
ется число позиционных параметров в командной строке. Если позиционных
параметров нет, то в строках 11-19 активируется цикл while. Заметим,
что цикл while выполняет оператор чтения, но не указывает, откуда дол-
жен быть взят его вход. Это связано с тем, что входом по умолчанию яв-
ляется стандартный ввод (stdin). Для каждого имени файла, которое чи-
тается из стандартного ввода, запускается команда file системы UNIX.
Выход команды file передается по программному каналу команде fgrep (а
не grep, что увеличивает скорость), чтобы посмотреть, является ли файл
текстовым.
Фактический выход команды fgrep перенаправляется на нулевое уст-
ройство (в бесконечную область памяти), поскольку он нам не нужен.
Нас интересует лишь код возврата после выполнения всего конвейе-
ра. Если команды file и fgrep отработали успешно, кодом возврата явля-
ется ноль. Это истинное значение, поэтому выполняется участок цикла
после then (строки 14-17). Если файл не существует или не является
текстовым, то код возврата ненулевой, и условный оператор завершается.
Это приводит нас в конец цикла, выполняется следующая итерация цикла
while и мы рассматриваем следующий аргумент из стандартного ввода.
Теперь рассмотрим обработку, выполняемую по then (строки 14-17).
Для каждого файла, который является текстовым, печатается строка двое-
точий (:) до и после имени файла, а команда head системы UNIX печатает
первые 15 строк. Такой сценарий продолжается, пока не закончатся дан-
ные в стандартном вводе.
Рассмотрим другую альтернативу, покрываемую данным оператором вы-
бора. Она обрабатывает ситуацию, когда имеется несколько позиционных
параметров (что указано символом * в операторе case). Цикл for пробе-
гает все параметры (строка 20). Звездочка (*) в операторе case означа-
ет, что подходит любое значение, которое не подошло ранее. Это улавли-
вающая (catchall) опция. Цикл for использует аргумент $* в качестве
своего входа. Он представляет значения всех позиционных параметров,
что является фактически всей командной строкой, исключая имя утилиты.
Команда find используется для поиска всех нормальных файлов в ка-
талоге. "Нормальные" файлы не означает "только текстовые файлы", поэ-
тому мы проверим это позже. Выход команды find передается по каналу
команде sort, чтобы сделать его более наглядным. Отсортированный
список передается по каналу в цикл while, который помещает имя файла в
переменную FILE (строка 27). Проверяется, текстовый ли файл, затем он
печатается командой head.
Если мы сравним строки 13-18 и строки 24-29, то мы увидим, что
это один и тот же код. В большинстве языков программирования это озна-
чало бы, что мы должны оформить эти строки как процедуру и вызывать
ее, когда нужно. Язык программирования интерпретатора shell, хотя и
довольно мощный, не имеет хорошего способа реализации процедур.
Последний интерпретатор shell в System V имеет функции, которые позво-
ляют решить эти проблемы.
Отметим, что внутренний цикл while повторяется на каждом файле,
который существует в определенном каталоге, а внешний цикл for прохо-
дит от каталога к каталогу.
Для увеличения гибкости хорошо бы добавить опции, чтобы вы могли
переходить на команду find непосредственно из thead. Полезными аргу-
ментами были бы -name для изолирования образцов имен файлов и -ctime
для обработки изменений, связанных со временем.
Еще одной привлекательной особенностью было бы добавление опции
грамматического разбора (основанной на -) и опции -n, указывающей, что
из команды head должно быть напечатано n строк.
В чем отличие между двумя следующими операторами?
$ find $HOME -name "*.c" -print | thead
и
$ find $HOME -name "*.c" -exec head {} \;
Они выглядят очень похоже, и они действительно похожи. Они обра-
батывают одни и те же файлы и печатают одни и те же данные из каждого
файла. Основное отличие в том, что строка, которая использует thead,
печатает хорошее оформление вокруг имени файла, а чистая команда find
печатает непрерывный поток текста так, что очень трудно определить,
какой файл вы просматриваете.
2.1.3. tgrep - поиск строк в дереве файловой системы
ИМЯ: tgrep
tgrep Поиск строки по шаблону в дереве файлов
Обходит файловое дерево и ищет в каждом файле указанную строку.
Если не указан никакой каталог, tgrep действует как фильтр.
tgrep [-c|-h] string [file ...]
# tgrep "profanity" /
Поиск слова "profanity" по всей системе (суперпользователь снова
на тропе войны!)
1 :
2 # @(#) tgrep v1.0 Search for string in tree Author: Russ Sage
2а Поиск строки в дереве
4 OPT=""
6 for ARG in $@
7 do
8 if [ "`echo $ARG|cut -c1`" = "-" ]
9 then case $ARG in
10 -c) OPT="-name \"*.c\""
11 shift;;
12 -h) OPT="-name \"*.h\""
13 shift;;
14 *) echo "$O: incorrect argument" >&2
15 echo "usage: $O [-c|-h] string [file ...] >&2
16 exit 1;;
17 esac
18 fi
19 done
21 case $# in
22 0) echo "$O: argument error" >&2
23 echo "usage: $O [-c|-h] string [dir ...]" >&2
24 exit 2
25 ;;
26 1) while read FILE
27 do
28 grep -y "$1" $FILE /dev/nul
29 done
30 ;;
31 *) STRING=$1; shift
32 eval find "$@" -type f $OPT -print | sort | while read FILE
33 do
34 grep -y "$STRING" $FILE /dev/null
35 done
36 ;;
37 esac
ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ
FILE Содержит имя каждого файла
OPT Содержит специальные опции команды find
STRING Временная переменная, в которой содержится строка
поиска
ОПИСАНИЕ
ЗАЧЕМ НАМ НУЖЕН КОМАНДНЫЙ ФАЙЛ tgrep?
Как мы могли видеть на примере двух предыдущих утилит, рекурсив-
ный просмотр файлов очень полезен. Он сохраняет время, поскольку поз-
воляет избежать поиска файлов вручную, а также создает средства, кото-
рые могут быть использованы в более мощных утилитах. Чем больше име-
ется созданных нами средств, тем больше новых средств мы можем постро-
ить с их помощью. Единственная проблема заключается в том, что вы
должны позаботиться об их взаимозависимости (каким утилитам или
средствам требуются другие утилиты или средства и кто на кого влияет).
Еще одна область, где UNIX не имеет "родной" рекурсивной команды
- это обработка строк. Семейство команд типа grep очень велико, но все
они работают только по одному фиксированному маршрутному имени файла.
Нам необходим препроцессор для команды grep. Правда, мы можем дать
запрос на все файлы во всей системе или какой-либо ее части по нашему
выбору. Если мы попытаемся сделать это вручную, то это означает, что
мы должны много раз нажимать на клавиши, что может привести к син-
таксической ошибке. Вы также должны точно помнить, как вы создавали
командную строку, если вы в следующий раз захотите выполнить такую же
задачу. Зачем выполнять грязную работу? Для этого существует компь-
ютер.
Создавая программу автоматического обхода дерева файлов, мы осво-
бождаемся для того, чтобы направить нашу энергию на более важные вещи
вместо того, чтобы выпутываться из ситуации в случае какого-либо слиш-
ком специфичного синтаксиса. Один раз создав достаточно мощные
средства доступа к файлам, мы можем посвятить наше время написанию
программ, обрабатывающих файлы данных для решения каких-либо задач.
ЧТО ДЕЛАЕТ tgrep?
Основным предназначением tgrep является обеспечение большей гиб-
кости и легкости использования возможностей команды grep. Ее синтаксис
точно такой же, как и у grep, за исключением допустимых типов файлов.
В команде grep UNIX в качестве аргумента может указываться практически
любой файл, но указание текстового файла имеет наибольший смысл. В ко-
манде tgrep также могут использоваться текстовые файлы, но наибольший
смысл имеет указание каталогов, поскольку мы ищем имена файлов. Коман-
да find работала бы не очень хорошо, если бы пыталась извлечь множест-
во имен файлов из текстового файла. В командной строке может указы-
ваться множество имен каталогов, поскольку все они используются как
начальное место поиска оператора find.
По умолчанию tgrep находит все обычные файлы. В этой программе
нет никакой проверки на то, текстовый файл или нет, поскольку мы не
пытаемся напечатать все на экран. Поэтому мы ищем строки символов во
всех файлах, начиная от архивных и заканчивая исполняемыми.
Если вы хотите выбрать типы файлов, используйте две опции, -c и
-h. Опция -c заставляет команду UNIX find искать только файлы с имена-
ми вида *.c. Аналогично, опция -h соответствует файлам *.h. Эти опции
могут быть полезны для управления программами на языке Си, с которыми
мы более детально познакомимся в главе 4. Эти опции не самое важное,
но они показывают, как легко добавить новые опции в программу.
Если при вызове была указана какая-то иная опция, кроме упомяну-
тых, выводится сообщение об ошибке и программа останавливается. Подоб-
но thead, tgrep является фильтром.
1. $ tgrep unix $HOME
Поиск любого вхождения слова unix во всех файлах моего регистра-
ционного каталога.
2. $ tgrep -c "^sleep()$" $HOME/src
Поиск выражения (начало строки, символьная строка, конец строки)
во всех исходных файлах на языке Си в регистрационном каталоге с
исходными текстами (опция -c).
3. # find /usr/src -name "*.c" -print | tgrep "ioctl"
Поиск всех вызовов ioctl в исходных Си-файлах, начиная с каталога
/usr/src. (Обратите внимание, что я являюсь суперпользователем. Это
видно из того, что я занимаюсь поиском в ограниченной части системы, а
именно в исходных дистрибутивах, а также из того, что в качестве сим-
вола приглашения используется символ "#".)
4. $ tgrep "| more" `find . -type f -print`
Поиск символа вертикальной черты (|), после которого следует сло-
во more, в списке имен файлов, генерируемом оператором find. Find пе-
чатает имена всех файлов текущего каталога и всех подкаталогов, кото-
рые являются обычными файлами.
5. $ tgrep trap /bin /usr/bin /etc
Поиск команды прерывания (trap) во всех командных файлах интерп-
ретатора shell, которые имеются в трех каталогах.
В строке 4 переменная OPT, в которой хранятся необязательные ко-
манды оператора find, инициализируется в нулевое значение.
Строки 6-18 выполняют проверку на наличие ошибок. Проверяется,
является ли первым символом каждого позиционного параметра символ "-".
Если проверка успешна, то проверяется на корректность сам аргумент.
Возможными опциями являются -c и -h. Если указано что-либо другое, вы-
водится сообщение об ошибке и программа завершается. Обратите внима-
ние, что с помощью команды shift допустимые опции удаляются из команд-
ной строки. Это сделано для того, чтобы впоследствии выражение $@ мог-
ло быть использовано для получения только аргументов строки поиска и
маршрута. Выражение $@ является другой формой выражения $ *, в которой
оно распространяется на все позиционные параметры. Однако в последую-
щем тексте мы увидим одно большое отличие между ними.
Еще один трюк сделан при присвоении значения переменной OPT в
строке 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.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, сталкива-
ясь с какой-либо проблемой, не борются с ней с помощью Си или команд-
ного файла интерпретатора shell. Поскольку они знакомы с существующими
ресурсами системы UNIX, они могут рассмотреть проблему и выбрать стра-
тегию, использующую наименее сложное средство, выполняющее данную ра-
боту с приемлемым уровнем производительности. В порядке возрастания
сложности, это могут быть непонятная, но существующая команда и/или
опция, псевдоним, командный файл интерпретатора shell или программа на
языке Си.
ЧТО ДЕЛАЕТ lc?
Общий подход к разработке этой команды заключается в том, чтобы
собрать вместе некоторые опции и сделать новую команду с более мощным
интерфейсом. Чтобы достичь этой мощи, мы можем сделать пре- или пост-
процессор для обычной команды системы UNIX.
Главная задача здесь - печать колонок, поэтому мы смотрим на оп-
ции команды ls, чтобы задействовать их. Конечно, мы включаем опцию -C.
Какие еще опции ls нам нужны? Обычно UNIX не печатает файлы, имена ко-
торых начинаются с точек, например, .profile, если только вы не указы-
ваете ls -a. Это забывается при просмотре этих важных файлов, поэтому
мы конструируем нашу команду так, чтобы она печатала их по умолчанию.
Никакие файлы не скрываются от нас. Для пользователей System V и BSD
(или для любого, кто имеет опцию -F), листинг улучшается за счет выво-
да "/" после имени каталога и "*" после исполняемого файла. Ранняя ко-
манда ls системы UNIX не имела возможности печатать в таком стиле. От-
метим, что данное использование термина "исполняемый" означает показ
того, что флаги прав доступа имеют бит "x", а не то, что это файл типа
a.out с магическим числом. Это отличие важно тем, что делает наш ко-
мандный файл более полезным.
Если ожидается длинная распечатка, как это бывает обычно для ре-
курсивных каталогов, то вы хотите иметь доступ к команде more. Мы
встраиваем команду more так, чтобы ее можно было активировать с по-
мощью опции -m. Опция -m должна быть первой опцией после имени коман-
ды, из-за способа, которым она проверяется внутри программы. Если она
передается после первой опции, она переходит к команде UNIX ls и ин-
терпретируется как печать в потоковом формате. Это такой формат, в ко-
тором все имена расположены в строках, разделенных запятыми (,). Как
мы уже отмечали, вы можете сделать интерфейс этого командного файла
более гибким за счет дополнительной работы над ним.
1. $ lc `path lc`
Получает полное имя для lc и распечатывает файловую информацию в
виде колонок.
2. $ lc -m -R /
Печатает колоночный список ВСЕХ файлов в системе, рекурсивно про-
ходя вниз по иерархии системного дерева и пропуская распечатку через
команду more.
Еще один маленький фокус: этот синтаксис был использован для соз-
дания другой команды, названной expose. Командная строка "lc -m -R $@"
давала бы рекурсивный список всех файлов в любом каталоге по вашему
выбору в приятном постраничном формате.
3. $ lc -m -R /usr/lib
Рекурсивно распечатывает список всех файлов во всех каталогах,
начиная с /usr/lib, и пропускает листинг через команду more.
4. $ lc -m . | more
Выдает список файлов в текущем каталоге и пропускает листинг че-
рез команду more, а затем снова пропускает все через more. Работает ли
это ? Никоим образом. Возникает полная путаница, и клавиша прерывания
обычно является наилучшим способом выхода из данной ситуации.
В строках 4-8 проверяется, является ли первым аргументом команд-
ной строки -m - опция команды more. Если эта опция найдена, то в пере-
менную MORE заносится указание конвейера и команда more. Тем самым
устанавливается постобработка, которую следует применить к выходу ко-
манды ls. Затем эта опция убирается из командной строки. Это делается
для того, чтобы остаток командной строки можно было передать команде
ls, не вызвав при этом нежелательных эффектов. Если первой опцией не
является -m, переменной MORE присваивается нулевое значение, чтобы она
впоследствии не влияла на командную строку.
Строка 10 - это командная строка, которую вы бы использовали на
старой UNIX-машине типа Version 7 или System III. Она не имеет ни
встроенной опции для печати символов косой черты (/) и звездочек (*),
ни возможности печати в виде колонок. Вы должны пожертвовать первой
возможностью, а распечатки в виде нескольких колонок можно получить с
помощью команды pr системы UNIX. Команда pr использована с опцией
"-5t", поэтому она печатает в пять колонок (что обычно приемлемо, но
если встречаются длинные имена файлов, то пяти колонок может оказаться
слишком много) и не печатает верхний и нижний колонтитулы. Благодаря
отказу от колонтитулов, 24-строчный формат не слишком неудобен для
вас.
Отметим, что здесь использована команда eval. Это специальная
встроенная команда интерпретатора shell, которая выполняет перевы-
числение текущей строки, подлежащей выполнению. Интерпретатор shell
повторно анализирует эту строку, чтобы раскрыть значение имен перемен-
ных в командной строке и обеспечить распознавание переменных как тако-
вых. Здесь мы перевычисляем переменную MORE. Напомним, что мы помести-
ли в эту переменную конвейер. Если мы не перевычислим командную стро-
ку, то команда pr попытается открыть файлы "|" и "more", которые не
существуют. Для того, чтобы shell вместо этого воспринял эти символы
как указания конвейеров и программ, и используется команда eval.
Строка 10 имеет еще одну особенность. В командной строке уже есть
один конвейер. Откуда shell знает, трактовать ли символ "|" как имя
файла или как конвейер? Благодаря тому, что аргумент команды eval зак-
лючен в кавычки. Это указывает команде eval сохранить все, что нахо-
дится в кавычках, без изменений, но раскрыть значение переменной MORE
и поместить его в конец командной строки, находящейся в кавычках.
Несколько непонятно, но если вы думаете об этом пару лет, оно стано-
вится осмысленным.
Для тех из вас, кто имеет новую команду ls (System V, версия 2
или BSD 4.2), не требуется два конвейера в команде. Как показывает
строка 11, мы получаем подходящий колоночный формат из самой команды
ls, вместе с показом всех файлов и специальными символами / и * для
каталогов и исполняемых файлов. Обозначение $@ относится ко всему со-
держимому командной строки, т.е. к вашим дополнительным опциям команды
ls и к именам файлов, список которых вы хотите распечатать. Поступая
таким образом, мы создаем фундамент (опции a,C,F), а вы можете
надстраивать его (используя опции R,t и т.д.). Скромный, но элегантный
фокус заставить ls сообщить свои опции заключается в том, чтобы выз-
вать ее с неверной опцией. Большинство команд не используют опции z
или ?, поэтому вызов "ls -z" или "ls -?" приведет к такому результату:
|
| ls: illegal option -- z
| usage: -1ACFRabcdfgilmnopqrstux [files]
|
Все эти опции представляют определенный интерес. Если вы часто
используете какие-либо из них, поместите их в командный файл lc, и вы
получите вашу собственную адаптированную команду.
Вы обратили внимание, что все обычные команды системы UNIX,
используемые в нашем командном файле, имеют полные маршрутные имена?
Это может показаться несколько странным, но причина указания полных
маршрутных имен в том, что когда shell запускает команду, он не должен
возвращаться к анализу переменной PATH и искать, где расположена ко-
манда. Если вы обращаетесь к командам относительным способом, время
поиска файлов представляет собой большие накладные расходы. Когда вы
вызываете lc, интерпретатор shell ищет эту команду, затем lc вызывает
ls, которую тоже нужно найти. Если после этого результаты пропускаются
через more или pr, то требуется дополнительный поиск. А полные марш-
рутные имена распознаются интерпретатором shell сразу же (он видит,
что первым символом является /), и нужная команда может быть вызвана
быстро. Издержки на поиск - единственные издержки команды lc.
Использование полных имен, естественно, требует, чтобы вы знали,
где в системе размещены утилиты, к которым вы хотите обратиться. Вы
можете применить команду paths, чтобы получить корректные полные имена
для жесткого указания их в тексте вашего командного файла, а можете
переписать данный командный файл при переходе в другую систему. Это
просто еще одна иллюстрация универсального компромисса между скоростью
и эффективностью, с одной стороны, и гибкостью и мобильностью, с дру-
гой.
2.2.2. ll - вывод файловой информации в длинном формате
ИМЯ: ll
ll Выдает список файлов в длинном формате
Выдает список файлов в длинном формате (-l). Распечатку можно
пропустить через команду more.
ll [-m] [ls options] file [file...]
ll *.c Выдача списка файлов с исходными текстами на
языке Си в длинном формате.
1 :
2 # @(#) ll v1.0 Long listing of files 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 -al $@ MORE
ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ
MORE Содержит строку передачи результатов по
конвейеру команде more
ОПИСАНИЕ
ЗАЧЕМ НАМ НУЖЕН КОМАНДНЫЙ ФАЙЛ ll?
Мотивы для создания команды ll те же, что мы обсудили ранее для
команды lc. Мы можем использовать ll для нескольких целей. Она умень-
шает количество требуемых нажатий на клавиши, позволяет избежать необ-
ходимости помнить специальные опции и вообще настраивает систему соот-
ветственно нашим требованиям вместо того чтобы нам приспосабливаться к
системе.
ЧТО ДЕЛАЕТ ll?
Основой этой команды является известная команда "ls -l". Она,
если вы помните, дает очень емкую информацию о каждом файле, включая
права доступа, связи, имя владельца, размер и так далее. (Кстати,
программисты, использующие язык Си, могут получить эту информацию при
помощи системного вызова stat(2).) Поскольку такой список при наличии
множества файлов может легко переполнить экран, то предоставляется оп-
ция -m. Она обеспечивает постраничный вывод с помощью команды more.
Отметим, что если используется эта опция, то она должна стоять первой.
Строка символов, соответствующая этой опции, удаляется командой shift,
так что она не смешивается с именами файлов и обычными опциями команды
ls, которые передаются как аргументы.
После опции -m (если она есть) ll допускает указание любых других
допустимых опций команды ls. Можно также использовать любую комбинацию
имен файлов. Здесь применимы обычные средства порождения имен файлов:
* соответствует любым символам, ? - одному символу, а символы [] зада-
ют диапазон из некоторого набора символов. В итоге мы получили команду
ls, которая по умолчанию работает как "ls -l", вызывает команду more с
помощью одной опции вместо необходимости указания конвейера в команд-
ной строке и при этом сохраняет гибкость команды ls.
1. $ ll /etc/*mount*
Выводит список всех файлов в каталоге /etc, имена которых содер-
жат в каком-либо месте слово mount (например, mount, umount,
unmountable).
2. $ ll -i `who|awk '{print "/dev/" $2}'`
Сперва выполняется команда who, затем результат ее работы по кон-
вейеру передается команде awk, которая вырезает имя устройства и при-
писывает ему префикс /dev/. В результате список полных маршрутных имен
ко всем терминальным устройствам, зарегистрированным в настоящий мо-
мент, помещается в командную строку команды ls -li. В распечатке ука-
зана вся информация об индексном дескрипторе файла (inode) для каждого
терминального устройства.
3. $ ll `kind -a /lib`
Выводит в длинном формате список всех файлов архива в каталоге
/lib. Этот каталог содержит библиотеки компиляторов всех языков систе-
мы UNIX. (Команда kind, которая отбирает файлы по их типу, рассматри-
вается в следующем разделе.)
4. $ ll -m -i /dev
Выводит всю обычную информацию плюс номер индексного дескриптора
для всех файлов в каталоге /dev. Выдача на экран происходит с помощью
команды more.
Если первым позиционным параметром является -m, то в строке 4
инициализируется переменная MORE для подключения конвейера и программы
/usr/bin/more. (Вопрос о том, почему используется абсолютное маршрут-
ное имя, обсуждался в предыдущем разделе.) Затем символьная строка -m
командой shift убирается из командной строки. Если же первой опцией не
является -m, то переменная MORE устанавливается в нуль, чтобы не вли-
ять на повторный разбор командной строки, выполняемый с помощью коман-
ды eval (строка 10).
В строке 10 команда eval использована для получения результирую-
щей командной строки. Команда ls вызывается с опциями -al (выдача
списка всех файлов в длинном формате), которые мы установили по умол-
чанию. Затем берутся аргументы командной строки (минус первый аргу-
мент, если это был -m, который мы убрали командой shift). Этими аргу-
ментами могут быть дополнительные опции команды ls плюс имена файлов
или каталогов. В конце строки значение переменной MORE обеспечивает
конвейер с командой more, если была указана опция -m. В противном слу-
чае значение переменной MORE равно нулю и не оказывает никакого влия-
ния на анализ содержимого командной строки.
Что произошло бы, если бы пользователь указал опцию -m в качестве
второй (или последующей) опции? В этом случае опция -m передалась бы
команде ls. Команда ls трактовала бы эту опцию как "потоковый вывод",
а это совсем не то, что мы хотели. Однако команда ls была вызвана так-
же с опцией -l, которая отменяет опцию -m в соответствии с текстом
программы ls. Вы не получили бы вывод с помощью команды more, но ваши
выходные данные по-прежнему были бы выведены в правильном формате.
2.2.3. kind - вывод однотипных файлов
ИМЯ: kind
kind Выдача списка имен файлов определенного вида
Выбирает и выводит имена всех файлов в указанном каталоге (ката-
логах), имеющих указанный тип. Если не указан никакой тип, выбираются
текстовые файлы.
kind [-a] [-d] [-t] [-x] [file...]
more `kind /etc/*`
Вывод командой more всех текстовых файлов, имеющихся в катало-
ге /etc.
1 :
2 # @(#) kind v1.0 Prints files of the same kind Author: Russ Sage
2а Выводит список файлов определенного вида
4 if [ $# -gt 0 ]
5 then if [ `echo $1 | cut -c1` = "-" ]
6 then case #1 in
7 -a) KIND='archive'
8 shift;;
9 -d) KIND='data'
10 shift;;
11 -t) KIND='text'
12 shift;;
13 -x) KIND='executable'
14 shift;;
15 *) echo "kind: arg error" >&2
16 echo "usage: kind [-a] [-d] [-t] [-x] [file...]" >&2
17 echo " -a archive" >&2
18 echo " -d data" >&2
19 echo " -t text, default" >&2
20 echo " -x executable" >&2
21 echo " if no args, reads stdin" >&2
22 exit 1;;
23 esac
24 fi
25 fi
27 : ${KIND:='text'}
29 case $# in
30 0) while read FILE
31 do
32 file $FILE | fgrep $KIND | cut -d: -f1
33 done;;
34 *) file $@ | fgrep $KIND | cut -d: -f1;;
35 esac
ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ
FILE Содержит имена файлов по мере их чтения из stdin
(стандартного ввода)
KIND Содержит строку, определяющую тип файла
ОПИСАНИЕ
ЗАЧЕМ НУЖЕН КОМАНДНЫЙ ФАЙЛ kind?
Файловая система UNIX имеет строгие стандарты при рассмотрении
файлов. Имеется три вида файлов: обычные файлы (тексты, данные, испол-
няемые файлы), каталоги и устройства. Каждый вид файлов имеет свое
предназначение и обычно имеет особые команды или файлы данных, которые
работают с ним.
Давайте рассмотрим, как некоторые из существующих команд системы
UNIX рассматривают типы файлов. Команда ls делает различие между ката-
логами и другими файлами, поэтому она может быть полезна. Другой важ-
ной командой является команда file. Она сообщает вам, какой тип имеет
данный файл, что потенциально полезно, но слишком мало. Для того чтобы
извлечь из команды file какую-либо полезную информацию, вы должны
надстроить над ней некоторую программу. Что нам действительно нужно,
так это некий гибрид команд ls и file, т.е. утилита, которая выводит
имена всех файлов указанного типа.
Примером полезности такого рода утилиты может служить анализ со-
держимого каталогов. Возьмем, например, каталог /etc. Он содержит
программы, файлы данных и текстовые файлы. Для каждого из этих типов
требуется свой собственный тип анализа. Программы анализируются коман-
дами ls, size, nm и file. Файлы данных анализируются командой od.
Текстовые файлы анализируются командами more, wc, head, tail и други-
ми. Таким образом, обычно вам необходимо работать в данный момент вре-
мени с файлами какого-нибудь одного типа.
ЧТО ДЕЛАЕТ kind?
Командный файл kind - это утилита, которая распечатывает имена
всех файлов, имеющих указанный тип. Она имеет интерфейс, похожий на
интерфейс команды ls, т.е. вы можете передать ей опции и имена файлов
или символы расширения имен файлов. При выводе отображаются полные
имена, если они были указаны, но вы можете избежать появления лишней
информации при выводе, если предварительно перейдете в нужный каталог
с помощью команды cd. Например, если бы я находился в моем регистраци-
онном каталоге (/usr/russ) и ввел команду
$ kind -d /etc/*
то вывод мог бы выглядеть так:
|
| /etc/mnttab
| /etc/utmp
| /etc/wtmp
|
То есть, вывелся список всех файлов данных. А если бы я выполнил
такую последовательность команд:
$ cd /etc
$ kind -d *
то при выводе убрался бы маршрут, использованный в вызывающей последо-
вательности, и напечаталось бы следующее:
|
| mnttab
| utmp
| wtmp
|
Затем выход в таком виде может быть использован во внешней коман-
де для распечатки и анализа файловой информации.
Допустимыми опциями команды kind являются -a для файлов архивов,
-d для файлов данных, -t для текстовых файлов (что является умолчани-
ем) и -x для исполняемых файлов. Определение этих типов соответствует
команде UNIX file. Заметим, что критерии того, что файл является
исполняемым, в команде file отличаются от тех, которые применяет ко-
манда ls: ls проверяет биты x в индексном дескрипторе файла, в то вре-
мя как file проверяет, являются ли первые несколько байтов содержимого
файла "магическим числом". Это магическое число является идентификато-
ром структуры a.out (см. /usr/include/a.out.h), который сообщает "Я
являюсь скомпилированной Си-программой".
Имена файлов появляются в командной строке после опций. Эти имена
могут быть порождены любым стандартным методом системы UNIX. Если в
командной строке нет имен файлов, то kind превращается в фильтр и чи-
тает стандартный ввод для получения списка имен файлов. (Обратите вни-
мание, что я сказал "имен файлов", а не "файлов". Можно использовать
опции, поскольку они убираются из командной строки командой shift по
мере того, как они встречаются.) Таким образом, вы можете использовать
другие команды для того, чтобы передать по конвейеру список файлов
утилите kind. Она отфильтровывает и выводит только те из них, которые
соответствуют нужному вам типу.
1. $ od `kind -d /etc/*`
Выглядит так, как будто это должно работать, но команда od не ра-
ботает с набором имен файлов. Она может обрабатывать только один файл
в данный момент времени.
2. $ ll `sh -x kind -a /lib/*` | m
Это длинный пример. Выводит в длинном формате список всех файлов
архивов, которые находятся в каталоге /lib. Мы запускаем shell в отла-
дочном режиме выполнения, так что вы можете увидеть каждую командную
строку перед ее выполнением. Результат по конвейеру передается команде
more.
3. # find / -print | kind -x | while read FILE
> do
> ll $FILE
> done > /tmp/filelist
Данный цикл обнаруживает все действительно исполняемые файлы. Для
каждого из них выполняется команда "ls -l". Отметим, что здесь команда
ll вызывается для каждого имени файла.
Вы могли бы выполнить ту же операцию при помощи такого оператора
find:
# find / -perm -0111 -exec ll {} \;
но опция perm в данном случае опять же проверяет биты прав доступа в
индексном дескрипторе файла, а не ищет магическое число в структуре
a.out, как описано ранее. Кстати, для того, чтобы вы могли успешно за-
пустить команду file (и тем самым kind) на системных файлах, вы должны
иметь права чтения, чтобы можно было прочитать магическое число.
4. $ for F in `kind /bin/* /usr/bin/* /etc/*`
> do
> fgrep "trap" $F /dev/null
> done
$ fgrep "trap" `kind /bin/* /usr/bin/* /etc/*`
$ find /bin /usr/bin /etc -exec fgrep "trap" {} \;
Это три различных способа поиска слова "trap" во всех текстовых
файлах.
Опции, которые могут быть указаны в командной строке, должны быть
самым первым аргументом. Это создает более строгий синтаксис, по кото-
рому можно выловить ошибку. Но это несколько ограничивает гибкость.
Как было ранее отмечено, вы можете, если хотите, по-своему разрешить
компромисс между эффективностью и гибкостью путем дополнительного
программирования.
В строке 4 проверяется, включены ли какие-либо параметры. Если
параметры есть, то они обрабатываются. Если не используются никакие
параметры, ничего не делается и управление передается на строку 27.
Если были использованы какие-либо аргументы и первым символом яв-
ляется знак минуса (-), то выполняется оператор case для определения
того, какой тип файла указан. Переменная KIND устанавливается в соот-
ветствии с типом файла, и данный параметр удаляется из командной стро-
ки командой shift. Если аргумент не совпадает ни с одной из допустимых
опций, то ему соответствует случай *, что означает ошибку. На стан-
дартное устройство регистрации ошибок выводится соответствующее сооб-
щение об ошибке и синтаксическая подсказка, после этого kind заверша-
ется с плохим статусом выполнения.
В строке 27 производится проверка того, установлена переменная
KIND или равна нулю. Если она равна нулю, в нее подставляется символь-
ная строка "text". Если KIND уже установлена, то она не меняется. Это
неплохой оператор присвоения значения по умолчанию. Таким образом,
пользователь не обязан указывать опцию -t в командной строке. Если же
опция -t была указана, то ей есть что сопоставить в операторе case.
Оставшаяся часть программы в строках 29-35 представляет собой еще
один оператор case, который проверяет количество аргументов, остав-
шихся в командной строке после обработки ошибок. Если была указана ка-
кая-либо опция, то переменная KIND установлена и опция убрана командой
shift. В командной строке могли остаться только аргументы, которые яв-
ляются именами файлов или маршрутами. Если к тому времени, когда мы
уже готовы к заключительной обработке, не осталось никаких аргументов,
то значит в командной строке не было указано ни одного имени файла.
В этом случае в строках 30-33 организовывается цикл, который чи-
тает имена файлов из стандартного ввода, запускает команду file и
использует команду fgrep для определения того, соответствует ли тип
файла, выданный командой file, интересующему нас типу (хранимому в пе-
ременной KIND). Затем мы используем команду cut для выделения того,
что нам нужно. Обычный вывод команды file содержит имя файла, двоето-
чие и затем описание. Нам нужно только имя файла, поэтому мы вырезаем
первое поле, используя разделитель ":". Когда никакие данные больше не
поступают, цикл while завершается, мы попадаем в конец оператора case
и выходим из программы.
Если же аргументы НАЙДЕНЫ в командной строке, то вместо всего
этого выполняется ветвь оператора case в строке 34. С помощью обозна-
чения $@, имена всех файлов в командной строке включены в команду
file. Таким образом, не нужен никакой цикл. Во всем остальном обработ-
ка идентична строке 32.
Было бы неплохо, если бы командный файл kind мог работать однов-
ременно с разными типами файлов. Это означает наличие несколько опций
в командной строке, например -a и -d. Вам могла бы понадобиться
составная строка, в которой каждая часть была бы отделена символом |.
Затем эта строка могла бы быть использована в команде egrep, например,
"egrep 'archive|data'". Вам пришлось бы организовать цикл по командной
строке вместо использования фиксированных позиций и убедиться в том,
что вы не получите зациклившийся конвейер, когда задана только одна
опция.
2.2.4. m - простой доступ к команде more
ИМЯ: m
m Простой доступ к команде more
Обеспечивает быстрый и простой способ постраничного вывода
m [more options] [file ...]
m * Вывод командой more всех файлов текущего каталога
1 :
2 # @(#) m v1.0 Easy access to more
2а Простой доступ к команде more
4 /usr/bin/more $@
ОПИСАНИЕ
ЗАЧЕМ НУЖЕН КОМАНДНЫЙ ФАЙЛ m?
Система UNIX сильно загромождается по мере своего функционирова-
ния. В ней обычно имеется множество текстов и данных. Просмотр громад-
ного количества данных требует многократного нажатия на клавиши, если
вы должны вручную управлять постраничным выводом или периодически вы-
зывать команду more. Нам необходимы программные средства, которые по-
могут нам ускорить эту работу. Одним из таких средств является m. Оно
очень короткое и простое, но это не значит, что оно бесполезно.
Имеется два основных способа вывода данных на экран. Первый
способ - непосредственный вызов команды, например, "more datafile". Вы
направляете данные на экран самой командой. Второй способ - использо-
вать какую-нибудь команду для получения данных, а затем в конце перех-
ватить их командой more, например "od -c . | more". В обоих этих слу-
чаях мы вводим с клавиатуры много символов. Сделав так, чтобы команда
more вызывалась по одному символу, мы могли бы уменьшить последние две
команды на шесть нажатий на клавиши. За целый день это хоть немного
предохранит клавиатуру от разрушения! (Если ваша система поддерживает
вызов команд по псевдонимам (aliasing), то, как указывалось ранее, вы
могли бы использовать в этом случае команду alias: "alias m more".)
ЧТО ДЕЛАЕТ m?
Надеемся, все ваши системы имеют команду more или хотя бы ее за-
мену. Постраничный вывод имеет важное значение при работе с текстом
большого объема.
Все опции и аргументы передаются в командной строке. Вы можете
указать опции команды more в командной строке команды m. Они переда-
ются без изменений. Можно указать имена файлов. Если они указаны, ко-
манда more выводит их. В противном случае ожидается поступление данных
со стандартного ввода. Таким образом, m может быть использована в ка-
честве "перехватчика" или как фильтр, как и команда more.
Для тех, кто не слишком знаком с опциями команды more, отметим,
что существуют две изящные возможности: 1) вход в редактор vi в том
месте, где находится курсор при выводе командой more; 2) выход из more
для запуска команды shell и возврат в то место, откуда вы вышли. Пер-
вая опция выполняется при нажатии клавиши "v" в строке состояния ко-
манды more. (То есть когда more отобразила полный экран текста и ждет
продолжения.) Вторая опция запускается при вводе ":!cmd" или "!cmd".
Когда команда выполнится, more вернется в то же место. Как видите, это
синтаксис командной строки ex. Команда more в самом деле имеет неболь-
шую часть редактора ex, спрятанную внутри нее. Вы можете выполнить
многие команды редактора, указывая их после подсказки в строке состоя-
ния команды more.
Обычный сеанс работы выглядит так:
|
| m `path termcap` <-поиск таблицы описания тер-
| минала (termcap) и вывод
| . ее командой more
.
.
--More--(5%) <-строка состояния more
v vi /etc/termcap
vi +210 /etc/termcap <-командная строка для редак-
тора vi получена от more
.
.
:q <-выход из vi
--More--(5%) <-возврат в more
:!sh порождение нового shell'а
$ date запуск команды date
Wed Apr 23 07:15:04 PST 1986
$ ^d <-убрать порожденный shell
--More--(5%) <-возврат в more
:f распечатка имени файла,
выводимого командой more
"/etc/termcap" line 54 выход команды f
--More--(5%)
f <-команда more для пропуска
полного экрана
.skipping 23 lines
.
.
--More--(9%) <-пропуск и выдача текста
q выход из команды more
1. $ ll -R / | m
Начиная с корневого каталога (/), вывести в длинном формате (ll)
все файлы (опция -a подразумевается в ll) всей системы (-R) и постра-
нично распечатать на экран (| m).
2. $ m `path inittab rc passwd`
Обнаружить и вывести с помощью more системные файлы inittab, rc и
passwd. Неприятность здесь заключается в том, что данный маршрут ско-
рее всего относится к каталогу /bin/passwd, а не /etc/passwd (посколь-
ку каталог /etc размещается в конце каталогов), а это означает, что вы
можете попытаться вывести на экран исполняемый файл. В зависимости от
того, какую из версий команды more вы запустили, это может привести к
чему угодно начиная с сообщения команды more о том, что это был не
текстовый файл, и заканчивая тем, что ваш терминал начнет показывать
непонятные символы и даже зависнет.
Поскольку в этом командном файле не так много текста, то все до-
вольно понятно, нет ни обработки ошибок, ни других дополнений. Просто
нехитрый вызов команды more. Полное имя здесь указано с целью повыше-
ния быстродействия, как мы обсуждали ранее. Вы должны перепроверить
местонахождение вашей команды more. В системе Berkeley она может нахо-
диться в каталоге /usr/ ucb/more. Воспользуйтесь командой path more
для определения этого места и вставьте соответствующий маршрут вместо
указанного нами.
Кстати, фокус попадания этой символьной строки в текст вашего ко-
мандного файла состоит в том, чтобы войти в редактор и вызвать следую-
щую команду:
:.!path more
Здесь происходит переход в shell и запуск команды path (:!), за-
тем выход команды path (который представляет собой полное маршрутное
имя) помещается в буфер редактора в самом начале текущей строки (.).
После этого вы имеете эти данные в вашем редактируемом файле и при не-
обходимости можете отредактировать их.
2.2.5. mmm - обработка программой nroff макрокоманд для рукописей
ИМЯ: mmm
mmm Командная строка nroff для макросов обработки
рукописей
Вызывает текстовый процессор nroff со специальными опциями, кото-
рые инициализируют макросы обработки рукописей.
mmm file [...]
mmm memo Обработать с помощью nroff файл моих заметок
memo и отобразить его на экран
1 :
2 # @(#) mmm v1.0 Nroff command line with mm macros Author: Russ Sage
2а Командная строка nroff с макросами mm
4 if [ "$#" -eq 0 ]
5 then echo "mmm: wrong arg count" >&2
6 echo "usage: mmm file [...]" >&2
7 exit 1
8 fi
10 LIST=""
11 for ARG in $*
12 do
13 if [ ! -f $ARG ]
14 then echo "mmm: $ARG is not a regular file" >&2
15 else LIST="$LIST $ARG"
16 fi
17 done
19 nroff -r0O -mm $LIST
ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ
ARG Содержит каждый позиционный параметр командной
строки
LIST Содержит список проверяемых имен файлов
ОПИСАНИЕ
ЗАЧЕМ НУЖЕН КОМАНДНЫЙ ФАЙЛ mmm?
Одним из фактов делового мира является работа с бумагами. Мы про-
изводим заметки, письма, контракты, документы, руководства и так да-
лее. Если вы знакомы со стилем производства документации в системе
UNIX, то ваши текстовые файлы в основном представлены в одном из фор-
матов программы nroff.
Однако различные программы форматирования текстов служат различ-
ным целям. Имеется стандартный nroff и nroffс дополнениями, такими
как макросы ms и mm. Для подготовки графической информации и выполне-
ния типографских работ разработана программа troff. Система AT&T имеет
целую программную среду под названием Writers Workbench, и система
Berkeley имеет аналогичные возможности.
Большинство наших задач по написанию каких-либо текстов может
быть сведено к нескольким стандартным форматам, таким как письма, ру-
кописи вообще, страницы руководств и так далее. Не так легко запомнить
опции команды nroff (или другой команды), которые следует использовать
в данном случае, да мы и не должны делать это. Наша команда mmm служит
иллюстрацией программы, которую мы можем запускать всякий раз, когда
нам нужен определенный формат. Вы можете создать несколько версий
программы, которые удовлетворяют вашим собственным нуждам при написа-
нии текстов.
Использование заготовленных заранее команд означает, что мы можем
делать полезную работу, даже если некоторое время мы не выполняли ра-
боту определенного вида. Мы также можем избежать многократных нажатий
на клавиши. Мастера UNIX'а периодически уединяются в своих горных убе-
жищах, где штудируют справочные руководства в поисках полезных, но
доселе незамеченных опций, которые могут быть встроены в программные
средства для повседневной работы. Если слишком некритично полагаться
на ваш текущий набор инструментальных средств, то можно пропустить по-
лезные возможности.
ЧТО ДЕЛАЕТ mmm?
Командный файл mmm - это интерфейсный процессор для команды
nroff. Под словом "интерфейсный" мы подразумеваем, что он обрабатывает
вызывающую командную строку и устанавливает все опции для вызова прог-
раммы nroff. Некоторые из опций nroff жестко запрограммированы в вызо-
ве. Эти опции инициализируют отдельные части программы nroff.
Если вы не включаете никакие аргументы, mmm распознает это как
ошибку и выводит синтаксическую подсказку. Обратите внимание, что если
вы передадите mmm такой аргумент, как -z, то этот аргумент будет
рассматриваться как имя файла, а не как подлежащая передаче опция, и
это снова вызовет ошибку. Вторая ошибка не является фатальной, в то
время как первая фатальна.
После обработки всех аргументов программа nroff использует имена
файлов в качестве файлов с входными данными. По умолчанию вывод произ-
водится в stdout (стандартный вывод). Обычно это экран вашего термина-
ла, но вывод может быть переадресован или передан по конвейеру на уст-
ройство печати или куда-либо еще.
1. $ mmm nroffile | m
Запуск команды nroff применительно к файлу nroffile, вывод ре-
зультата на экран с передачей по конвейеру команде more. Это полезно
при изучении утилиты nroff, проведении экспериментов с различными ко-
мандами и наблюдения за соответствующими результатами.
2. $ for F in proj.?
do
mmm $F > $F.rf
done
Обработка в цикле всех файлов, имена которых содержат символьную
строку "proj.", за которой следует один символ. Это могут быть proj.1,
proj.2 и так далее по всему набору символов вплоть до proj.z, proj.{,
proj.|, proj.} и proj.~, если считать, что у вас есть файлы, имена ко-
торых содержат эти символы. Каждый файл обрабатывается, и выход nroff
перенаправляется в файл с таким же именем, дополненным символами .rf.
3. $ mmm status[12] | lpr -o5
Обработка командой nroff файлов status1 и status2. Выход в стан-
дартный вывод передается по конвейеру программе lpr. Программа lpr яв-
ляется фильтром и принимает или имена файлов в командной строке, или
непосредственно данные, передаваемые ей по конвейеру (но не то и дру-
гое сразу). Опция -o5 указывает lpr сместить страницу на 5 символов.
В строке 4 проверяется, равно ли нулю количество аргументов в ко-
мандной строке. Если да, в стандартный файл ошибок выдается сообщение
об ошибке. Выводится также синтаксическая подсказка, и mmm завершается
с плохим статусом.
Переменная LIST инициализируется нулевым значением в строке 10.
Обычно переменные интерпретатора shell и так в начале равны нулю, но
предварительная установка значения является хорошим стилем программи-
рования.
Затем мы обрабатываем каждый аргумент командной строки в цикле
(строки 11-17). Все аргументы должны быть именами файлов, поэтому каж-
дый из них проверяется на то, существует ли он как обычный файл. Если
это не файл, то в стандартный файл ошибок выводится сообщение об ошиб-
ке. Тем не менее программа не завершается. Не следует аварийно прекра-
щать всю программу только потому, что нет указанного файла. Мы про-
пускаем его и идем до конца списка аргументов. Это особенно актуально,
если данная команда используется как фоновая во время выполнения дру-
гой работы. Пользователь скорее согласится с тем, чтобы было выполнено
побольше работы, чем не сделано вообще ничего. Это решение, принятое в
данной программе, и вы можете изменить его, если оно не подходит в ва-
шей ситуации.
Если имени соответствует допустимый файл, оно добавляется в
список хороших имен файлов. Этот список становится главным списком для
команды nroff.
После того как все аргументы проверены, мы в строке 9 строим и
выполняем командную строку nroff.
Опция -rO0 для nroff указывает макросам обработки рукописей (па-
кету mm) установить регистр, который имеет дело с отступом текста, в
состояние, соответствующее отступу в 0 символов. Это значит, что весь
текст начинается с крайней левой позиции, т.е. выровнен слева. Путем
проведения экспериментов я обнаружил, что левое выравнивание текста
программой nroff и установка отступа для принтера дает наиболее надеж-
ный вывод на печать. В противном случае, если вы установите отступ
текста в nroff и отступ в принтере, то может произойти настоящее столк-
новение, когда дело коснется вывода колонок в странице. Вы можете из-
менить это место, если ваши программы вывода или устройства печати ве-
дут себя как-то иначе. Опция -mm указывает программе nroff просмотреть
библиотеку макросов обработки рукописей, чтобы определить, использу-
ются ли какие-либо из них во входном документе. Эти макросы очень
большие и требуют много времени центрального процессора. Если вам не-
обходимо использовать их, то вам потребуется большой компьютер или
компьютер, специально предназначенный для этой цели, чтобы добиться
хорошего времени получения результата.
Последним аргументом является $LIST. В этой переменной находится
строка имен файлов, разделенных пробелами. Эти имена помещаются в ко-
мандную строку nroff. Можете быть уверенными, что в этом месте нет ни-
каких ошибок.
Поскольку все аргументы рассматриваются как имена файлов, то у
нас нет способа передачи дополнительных команд пакету mm. Наличие та-
кой возможности было бы желательным, поскольку при экспериментировании
с командой nroff вам необходимо пробовать различные опции, чтобы уви-
деть, как они действуют. Было бы тяжелой работой выполнять редактиро-
вание текста mmm, чтобы добавить одноразовые опции, которые могут вам
никогда не понадобиться или опции, которые вы должны постоянно менять.
Один из путей достижения большей гибкости - посмотреть, имеет ли
какой-либо аргумент дефис в качестве первого символа. Если да, перех-
ватить эту опцию и убрать ее из списка имен файлов. После этого вы бы
имели список опций, которые нужно включить в командную строку, и
список имен файлов, подлежащих обработке.
Отметим, что место, занятое в нашем командном файле указанием па-
кета mm, можно вместо этого заполнить ссылкой на другие макропакеты,
имеющиеся в вашей системе, например -ms или -me, в зависимости от нуж-
ного вам формата. Отказ от поиска макросов, которые вам не нужны,
ускорит обработку: подробности вы найдете в документации по nroff или
troff.
2.2.6. pall - печать всех файлов в дереве
ИМЯ: pall
pall Распечатка всех файлов в дереве каталогов
Находит все файлы в заданном каталоге в соответствии с некоторым
критерием, разбивает файлы на страницы и помещает результат в один
файл, готовый к распечатке на принтере.
pall [-t|-d] directory
pall /usr/lib
Выводит на печать постранично все текстовые файлы в каталоге
/usr/lib
1. :
2 # @(#) pall v1.0 Print all files in a tree Author: Russ Sage
2а Печатает все файлы в дереве
4 if [ $# -eq 0 -o $# -gt 2 ]
5 then echo "pall: wrong argument count" >&2
6 echo "usage: pall [-t|-d] dir" >&2
7 echo " -t text (default)" >&2
8 echo " -d dev (.c,.h,.mk,.s)" >&2
9 exit 1
10 fi
12 NAME=""
13 if [ `echo $1 | cut -c1` = "-" ]
14 then case $1 in
15 -t) NAME=""
16 shift;;
17 -d) NAME="-name \"*.[chms]*\""
18 shift;;
19 *) echo "pall: invalid arg $1" >&2
20 echo "usage: pall [-t|-d] dir" >&2
21 echo " -t text (default)" >&2
22 echo " -d dev (.c,.h,.mk,.s)" >&2
23 exit 1;;
24 esac
25 fi
27 echo "creating output file: /tmp/lpr$$"
29 eval find $1 -type f $NAME -print | sort | while read FILE
30 do
31 if file $FILE |
32 egrep 'exec|data|empty|reloc|cannot open' >/dev/null 2>&1
33 then continue
34 else file $FILE > /dev/tty
35 pr $FILE
36 fi
37 done >> /tmp/lpr$$
39 echo "\nSend /tmp/lpr$$ to line printer (y/n): \c"
40 read CMD
41 if [ "$CMD" = "y" ]
42 then lpr /tmp/lpr$$
43 fi
ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ
FILE Содержит имя каждого файла, который должен быть
обработан в цикле while
NAME Содержит строку поиска для определения местона-
хождения указанных файлов
CMD Содержит команду выдачи результатов на принтер
ОПИСАНИЕ
ЗАЧЕМ НУЖЕН КОМАНДНЫЙ ФАЙЛ pall?
Эта утилита объединяет концепции обхода дерева файлов и вывода
содержимого файлов. Даже когда файлы упрятаны в подкаталогах, мы все
равно хотим найти их. Нам необходима для этого утилита, которая обхо-
дит древовидную структуру файлов, находит файлы нужного нам типа, го-
товит их к распечатке и ставит в очередь для вывода на принтер.
Такого рода утилита особенно полезна, если исходные тексты или
файлы с документацией хранятся в иерархическом дереве. Дело осложня-
ется тем, что обычно эти текстовые файлы смешаны с исполняемыми файла-
ми (откомпилированными программами), файлами данных и, возможно, с ар-
хивными файлами. Необходимо иметь возможность отфильтровать все непри-
годные для печати файлы и подготовить текстовые файлы. Должны быть
проверены все файлы с тем, чтобы ни один не был пропущен.
Для выполнения всего этого процесса вручную требуется, чтобы вы
по команде cd переходили в каждый уровень дерева файлов, находили
текстовые файлы, обрабатывали их (обычно командой pr системы UNIX или
каким-либо другим текстовым процессором) и распечатывали их. После вы-
полнения всей этой работы вы еще должны собрать все отдельные распе-
чатки вместе в строго определенном порядке. Это большая работа, под-
верженная ошибкам со стороны человека. Почему бы не позволить машине
выполнять эту работу? Сейчас мы имеем концепции и средства, необходи-
мые для создания такой утилиты.
В дополнение к возможности управления файлами, pall также может
управлять устройством печати. Обычно каждое задание, поставленное в
очередь на выполнение к принтеру, имеет заголовок, который печатается
первым. Это значит, что если вы поставили в очередь на печать десять
отдельных заданий, то впереди каждого из них будет две-три страницы,
которые должны быть убраны вручную. Помножьте это на сотни файлов, и
вы будете иметь кучу бумаг, которые должны быть выброшены.
Pall исключает эти потери, поскольку все обработанные данные со-
бираются в один большой текстовый файл. Когда вся обработка выполнена,
этот один файл может быть поставлен в очередь на печать или сохранен
для некоторых других целей. Единственное ограничение при таком подходе
заключается в максимальном размере файла, который вы можете создать.
Этот размер вычисляется умножением значения ulimit на размер блока.
Например, мое значение ulimit равно 4096. Размер блока в данном случае
равен 512, а не 1024. Максимальный размер файла равен 2097152. Вы мо-
жете вычислить это прямо с клавиатуры, как показано ниже:
$ ulimit
4096
$ expr 4096 \* 512
2097152
Этого значения достаточно для большинства случаев.
ЧТО ДЕЛАЕТ pall?
Командный файл pall предназначен для поиска указанных файлов, об-
работки их командой UNIX pr и сборки всех результатов в один файл.
После того как все исходные файлы будут обработаны командой pr, вам
будет задан вопрос о том, хотите ли вы поставить выводной файл в оче-
редь на печать к принтеру. Результирующий файл сохраняется в каталоге
/tmp, где его можно использовать для других целей или удалить.
Опциями pall являются -t и -d. Опция -t используется по умолчанию
и нет необходимости ее указывать. Она предназначена для документации и
указана в командной строке, чтобы более ясно показать действие, кото-
рое будет выполнено.
Если выбрана текстовая опция, ищутся все файлы в древовидной
структуре и затем отбираются только текстовые файлы. Если указана оп-
ция разработки -d (development), то ищутся только файлы, связанные с
разработкой программ. Затем эти файлы отфильтровываются с целью полу-
чения текстовых файлов. Считается, что к разработке программ относятся
файлы, имена которых имеют вид *.c для исходных файлов на языке Си,
*.h для включаемых файлов заголовков, *.mk для файлов построения прог-
рамм (makefiles) и *.s для исходных файлов на ассемблере. Если требу-
ются какие-либо другие шаблоны, то такие символы могут быть легко по-
мещены в текст программы.
Прежде чем начнет выполняться поиск файлов, на экран выводится
имя временного файла, чтобы вы знали, как обратиться к нему после за-
вершения выполнения команды. Все результаты, полученные после обработ-
ки файлов, направляются в этот один файл. Командный файл pall также
выводит на экран сообщения, когда он обрабатывает файлы. Вывод файлов
выполняется в реальном времени по мере обработки файлов. Распечатка
производится при помощи обычной команды UNIX'а file. По распечатке вы
можете судить о том, файлы какого типа обрабатываются в данный момент.
Если какой-либо норовистый файл проскользнет, то вы знаете, где он
размещен и какого он типа. Это делает отладку гораздо более простой.
Для файлов выполняется обработка, которая является действием по
умолчанию команды pr. Она разбивает файл на страницы и ставит заголо-
вок в начале каждой страницы. Заголовок содержит дату, имя файла и но-
мер страницы. Нет никакого иного способа передать заголовок командному
файлу pall во время его работы, поскольку он предполагает, что вы хо-
тите знать имя каждого файла таким, как оно есть на диске. Изменение
строки заголовка вызвало бы только неприятности и дополнительную рабо-
ту.
Способ вызова pall влияет на формат имени файла в заголовке. Если
вы вызвали pall, используя абсолютное имя каталога, то в распечатке
используются полные маршрутные имена. Если вы вызвали pall с относи-
тельными маршрутными именами, то они и используются при выводе на пе-
чать. Внутри pall используется команда find системы UNIX. Команда find
использует данные из командной строки, т.е. те, которые ввел пользова-
тель. Выводимый заголовок изменяется в зависимости от того, что указа-
но в командной строке, которую использует find. Если вы вызываете
pall, используя следующую командную строку, то заголовок содержит пол-
ное маршрутное имя:
|
| $ pall /usr/include
|
| May 5 10:39 1986 /usr/include/a.out.h Page 1
| .
| .
| .
| May 5 10:39 1986 /usr/include/ar.h Page 1
| .
| .
| .
Если вы вызываете pall с помощью относительной нотации, то имена
файлов также являются относительными, что не очень хорошо. Если у вас
есть несколько каталогов, в которых имеются одинаковые имена файлов,
то вы не сможете быть уверены, что смотрите на правильную распечатку.
Вот как это может выглядеть:
|
| $ cd /usr/include
| $ pall .
|
| May 5 10:39 1986 ./a.out.h Page 1
| .
| .
| .
May 5 10:39 1986 ./ar.h Page 1
.
.
.
1. $ pall /usr/include
Выводит ВСЕ файлы заголовков. Сюда включаются файлы заголовков в
подкаталоге sys и во всех других каталогах, которые могут распола-
гаться ниже каталога /usr/include. Это и есть причина, по которой был
написан командный файл pall. Он создает один огромный листинг всех
файлов заголовков в отсортированном порядке с печатью в заголовке
страниц полного имени.
2. $ pall $HOME/src
Обходит все каталоги, находящиеся ниже каталога исходных текстов,
и распечатывает все файлы.
В самом начале производится проверка на наличие ошибок в команд-
ной строке. Если в ней нет аргументов или их больше двух, выводится
сообщение об ошибке, синтаксическая подсказка и программа завершается
с неудачным статусом возврата.
В строке 12 инициализируется переменная NAME. Это действие выпол-
няется по умолчанию, поэтому данная строка дает возможность не указы-
вать опцию в командной строке. Оператор if в строке 13 означает: "Если
первым символом первого аргумента является дефис", то нужно проверить,
какая это опция.
Если установлена опция -t, то переменная NAME инициализируется
нулевым значением, что совпадает с действием по умолчанию, поэтому на
самом деле ничего не меняется. Затем эта опция удаляется из командной
строки.
Если установлена опция -d, то переменная NAME инициализируется
для поиска символьной строки, соответствующей именам файлов программ-
ной разработки. Обратите внимание, что двойные кавычки внутри операто-
ра экранированы, т.е. впереди них стоят символы наклонной черты. Ко-
мандный интерпретатор shell воспринимает кавычки вокруг строки поиска
на первой фазе синтаксического разбора без отмены присвоения, тем са-
мым оставляя двойные кавычки последующей команде find.
Если опцией является что-либо другое, выводится сообщение об
ошибке и программа завершается.
В строке 27 выводится сообщение о том, какой файл содержит ре-
зультаты работы. Сам этот оператор не создает файл. Он только печатает
имя файла, который будет создан позже.
Строки 29-43 - это главный цикл всей программы. Оператор find
должен быть повторно проанализирован командой eval, поскольку перемен-
ная NAME содержит нужные нам данные. Если бы не было команды eval, то
подстановка символьных строк выполнялась бы неправильно. Обратите вни-
мание, что переменной NAME не требуются кавычки в строке 24. Они уже
есть в переменной NAME, так как были обработаны командой eval.
Оператор find находит только файлы типа f, или обычные файлы,
т.е. не каталоги и не символьные или блочные устройства. Здесь под
"обычными файлами" понимается, что они еще могут быть файлами данных
или исполняемыми. Если значение переменной NAME равно нулю, оно не
влияет на командную строку. Если NAME содержит символы файлов прог-
раммной разработки, то они становятся частью команды find при выполне-
нии команды eval. Это накладывает ограничения на шаблон поиска команды
find. Когда файлы найдены, их имена выводятся в стандартный вывод.
Стандартный вывод по конвейеру передается команде sort, располагающей
имена файлов по порядку. Это сильно помогает при сортировке горы вы-
водной информации. Чтение кипы распечаток толщиной в один фут может
свести с ума кого угодно.
Отсортированные имена по конвейеру передаются в цикл while, кото-
рый читает имена файлов по одному. Обратите внимание, что стандартный
вывод для всего цикла while переадресовывается во временный файл, что
облегчает сборку всех выходных результатов в одном месте вместо пере-
адресации каждого вызова команды в файл.
Для каждого подходящего файла выполняется проверка в строках
31-36. Проверка начинается с запуска команды file. Выход file по кон-
вейеру передается команде egrep, которая ищет тип файла, соответствую-
щий набору нескольких выражений. Если какое-либо выражение подходит,
то нам не нужно обрабатывать этот файл. Это не текстовый файл, и его
нельзя вывести на принтер. Во многих случаях файлы данных содержат
большое количество символов прогона формата, которые выталкивают стра-
ницу после каждой пары символов. Если вы не будете находиться рядом с
принтером, когда печатаются такие файлы, то вы можете получить
листинг, занимающий половину ящика бумаги, затратив целый лес на не-
нужную работу.
Нам не нужен выход команды egrep, а только ее статус возврата.
Если egrep обнаруживает одно из указанных ей выражений, она заверша-
ется со статусом успеха, или 0. Тем самым проверка if включает выпол-
нение оператора then, который в данном случае выводит нас из конструк-
ции if-then-else и продолжает цикл while, пропуская таким образом
файл.
Если же egrep не обнаружила ни одну из указанных символьных
строк, то выполнение продолжается с оператора else, который выполняет
еще одну команду file и переадресовывает ее вывод на устройство с име-
нем /dev/tty. Это универсальное имя устройства, которое гарантирует
вам вывод на экран вашего терминала. UNIX обеспечивает, что указание
/dev/tty обходит любые команды переадресации вывода, действующие в
данный момент. Поскольку стандартный вывод уже переадресован для всего
цикла while, то нам нужно попасть на устройство /dev/tty, чтобы вывод
шел на экран терминала, а не в файл печати. Отображение на терминал
имени обрабатываемого файла позволяет пользователю знать, какой файл
будет добавлен к распечатке.
Если файл удовлетворяет нашим критериям, он обрабатывается коман-
дой pr. Результат направляется в стандартный вывод, который переад-
ресован циклом while так, чтобы результат четко попадал в один файл.
Отметим, что нам нужно поставить символ добавления в файл вывода (>>).
В противном случае мы получим запись на место существующего файла пе-
чати, а значит в файле печати будет находиться только последний обра-
ботанный файл.
После того как все файлы обработаны, задается вопрос о том, хоти-
те ли вы вывести результирующий файл на печать. Предлагается ответить
на этот вопрос "да" (yes) или "нет" (no), однако в программе проверя-
ется только положительный ответ (yes). Это значит, что нажатие любой
клавиши трактуется как ответ "no", кроме клавиши "y", означающей "да".
Ответ пользователя читается с клавиатуры, и проверяется, является ли
он символом "y". Если да, то файл ставится в очередь на печать. Если
нет, дальнейшая проверка не производится и командный файл завершается.
Отметим, что запрос о выводе на печать поступил в стандартный вы-
вод. Переадресация вывода действовала только во время работы цикла
while, а затем прекратилась. Так было сделано потому, что цикл while
был фактически еще одним порожденным shell-процессом (subshell) и пе-
реадресация действовала только в этом те внимание, что маршрутная-
установите значения переменных вне цикла, а затем измените их внутри
цикла. После завершения цикла переменные по-прежнему имеют свои перво-
начальные значения, а не измененные в цикле значения. Измененные зна-
чения касались переменных порожденного интерпретатора shell, которые
исчезли, когда порожденный shell завершился. Переменные интерпретатора
shell могут передавать значения только вниз, порожденным процессам, но
процессы-потомки не могут передавать значения переменных вверх, роди-
тельскому процессу. Обычно передача значений переменных поддерживается
при помощи какого-либо файла, в котором хранятся данные для обмена
между родительским процессом и процессом-потомком.
УПРАВЛЕНИЕ ВЫВОДНЫМИ ФАЙЛАМИ БОЛЬШИХ РАЗМЕРОВ
Как мы уже отмечали, общий размер выводного файла ограничен. На-
помним, что команда find проходит все дерево каталогов вниз до конца
по всем поддеревьям, начиная с каталога, имя которого указано в ко-
мандной строке. Если вы находитесь на вершине очень глубокого дерева,
то обрабатываться могут буквально сотни файлов. Поскольку вы ограниче-
ны максимальным размером выводного файла, вы можете обработать только
ограниченное число файлов. Конечно, количество файлов, которое вы мо-
жете обработать, зависит также от того, насколько велики входные фай-
лы.
Если выводной файл достигает своего максимума, все добавляемые
после этого данные теряются. Потеря данных весьма болезненна, и обычно
требуется некоторое время, чтобы ее обнаружить. В медленно работающей
системе попытка обработать большое дерево, например все исходные
тексты системы UNIX, может занять целый час и даже больше, прежде чем
выходной файл заполнится. Это означает, что вы должны находиться рядом
и следить за тем, когда файл переполнится. Если он все-таки перепол-
нился, вы должны все выбросить и начать сначала. Это также означает,
что вы должны перейти вниз по дереву. Это может быть проблемой в сба-
лансированных деревьях.
Например, рассмотрим каталог /usr/lib. Этот каталог содержит мно-
го файлов на первом уровне и много каталогов первого уровня. Если бы
мы не обработали все файлы каталога /usr/lib за одну попытку, мы долж-
ны были бы пойти вниз по подкаталогам каталога /usr/lib. Попытки де-
лать это вручную и запускать pall в каждом подкаталоге заняли бы много
времени и могли бы привести к ошибкам с вашей стороны. Кроме того,
pall допускает указание только одного имени каталога, что приведет к
получению большого количества распечаток и к путанице при их сортиров-
ке.
Что же делать? Радикальным решением является увеличение значения
ulimit. Вы можете сделать это либо с помощью программы на языке Си,
использующей системный вызов ulimit, либо командой shell'а ulimit.
Техника выполнения такой работы представлена в главе 7.
Возможно, вы захотите добавить свои собственные штрихи в некото-
рых местах командного файла. Первым местом является то, где указыва-
ются символы поиска файлов программной разработки. Символы, использо-
ванные нами - это наиболее употребимые суффиксы в UNIX. Если вы
используете не Си и ассемблер, а другие языки, то вы можете добавить
соответствующие символы.
Следующим местом, где могут быть сделаны дополнения, являются оп-
ции, которые может понимать pall. Вам могут понадобиться файлы с опре-
деленными именами или определенными типами, например, файлы nroff. Эти
опции могут быть легко добавлены в оператор case, что улучшит команду.
Последним местом возможных изменений является тип файлов, которые
нужно пропускать. Символьная строка для команды egrep покрывает боль-
шинство важных нетекстовых типов файлов. В вашей системе могут быть
какие-то особые типы или же имена могут быть другими. Если вам необхо-
димо дополнить строку, сделайте это. Команда egrep может обработать
довольно много информации. Я не знаю ее ограничений. Возможно, вы об-
наружите их, просматривая исходный текст утилиты egrep. Если получа-
ется слишком длинная строка и не помещается на экране, ничего страшно-
го. Перенос на следующие строки экрана не опасен, пока общее количест-
во символов не превысит 255. Опасно только указывать переадресацию
символьной строки if на нулевое устройство в следующей после команды
egrep строке. Кажется, что все работает правильно, но это не так. Пе-
реадресация должна указываться в той же строке, где стоит команда
egrep.
В данной главе сделано очень много. Наиболее важно то, что полу-
чено множество новых идей, которые можно использовать при эксплуатации
программной среды и просмотре файлов любого типа. В следующей главе мы
углубимся в рутинную работу по ежедневному сопровождению файлов и
используем изученные средства, чтобы они облегчили нашу жизнь.
* ГЛАВА 1. Среда системы UNIX *
Введение
Многообразие сред системы UNIX
Ваш регистрационный каталог: как сделать его комфортным
Теории относительности a la UNIX
Жизнь системы UNIX: некоторые метафоры
В данной главе рассматривается среда, которая существует в систе-
ме UNIX и вокруг нее. Освещение всех аспектов среды UNIX было бы слиш-
ком громоздкой задачей и выходит за пределы данной книги. Даже отдель-
ным утилитам, таким как fsdb и sdb, нужны свои собственные книги, что-
бы отдать им должное. Мы пытаемся дать читателю начальные сведения,
философию и ощущение системы UNIX, что лежит в основе исследований и
инструментов, представленных в этой книге.
Читая эту главу, вы, возможно, захотите прочитать (или перечи-
тать) команды profile(4), environ(5), term(5), termcap(5) и termio(7)
в руководствах по UNIX, чтобы ознакомиться с механизмами, которые пре-
доставляет UNIX для установки рабочей среды.
Внутри системы UNIX существует множество различных подсред. Все
вместе они образуют общую картину, в виде которой мы представляем себе
UNIX. Эта книга посвящена наиболее важным аспектам среды UNIX с целью
закладывания фундамента, необходимого для понимания всей системы. Это
даст вам контекст, в котором можно посмотреть на собственную работу в
системе, независимо от того, являетесь вы пользователем, программистом
или администратором системы.
В данной главе рассматриваются различные среды в компьютерах с
теоретической точки зрения, описывается "домашняя" среда и методы ее
установки, способы использования условных обозначений и глобальная
среда.
Каждая компьютерная система поддерживает много различных сред.
Эти среды используются как строительные блоки для создания функцио-
нальных рабочих систем. Различные уровни необходимы как для сокращения
объема работы по управлению машиной, так и для построения такого ин-
терфейса, чтобы мы могли использовать компьютер на относительно высо-
ком, удобном для человека уровне.
Мы рассматриваем эту модель, так как она помогает выстроить в ряд
уровни, на которых мы можем работать. Имея больше знаний о том, где мы
находимся в системе, и о том, как она функционирует вокруг нас, мы мо-
жем легче строить растущие абстрактные модели на вершине тех моделей,
которые уже имеются. Компьютеры - это фактически рабочие модели
абстракций, так что чем больше мы понимаем модели, тем лучше мы можем
использовать их для упрощения и ускорения нашей работы.
Многообразие моделей на рис.1-1 . демонстрирует различные уровни,
функционирующие внутри компьютера. Нижний слой - это стартовая точка,
от которой многообразие растет вверх. Каждый уровень строится на пре-
дыдущем и используется для поддержки уровня, расположенного над ним.
Для каждого более высокого уровня среда более объемна и более "вирту-
альна" в том смысле, что имеет место меньше условных ограничений.
Верхние уровни используют для своей работы нижние и, таким образом,
скрывают подробности, необходимые для работы этих нижних уровней. Мы
можем создать модели высокого уровня, которые работают на машине более
низкого уровня, не зная ничего о нижних уровнях.
Давайте бросим беглый взгляд на уровни модели и поговорим о том,
какими из них оперирует данная книга.
Рис. 1-1
Многообразие компьютерных сред
\ L7 / Командные файлы (scripts)
\________________________________/
\ L6 / Прикладные программы,
\____________________________/ интерпретатор команд, языковые генераторы
\ L5 / Компилятор
\________________________/
\ L4 / Операционная система
\____________________/
\ L3 / Ядро
\________________/
\ L2 / Условная машина, ассемблер
\____________/
\ L1 / Микропрограммы
\________/
\ L0 / Логические схемы, аппаратные средства
\____/
УРОВЕНЬ 0 - АППАРАТНЫЕ СРЕДСТВА
На самом нижнем уровне находятся аппаратные средства и логические
цепи. Этот уровень определяет способ хранения и обработки данных во
всех аппаратных средствах. Поскольку технология изготовления кремние-
вых микросхем продолжает развиваться, этот уровень становится физи-
чески меньше и проще, тогда как скорости запоминания и обработки про-
должают расти. На этом уровне компонентами являются центральный про-
цессор (ЦП), память, микросхемы поддержки и системная шина.
Отметим, что хотя прогресс на этом уровне продолжается, это вызы-
вает очень малые изменения на верхнем слое пирамиды. Философия системы
UNIX состоит в том, чтобы изолировать низкоуровневый аппаратный слой и
обеспечить единообразные интерфейсы к нему, которые не нуждаются в из-
менениях "наверху". Верхний слой даже не должен знать о нижнем слое.
Это не значит, что события в мире аппаратуры не важны в реальном мире,
ведь противоречия реального мира влияют на скорость и емкость
ресурсов, не говоря уже об их стоимости.
Этот уровень во многом похож на язык программирования. Он явля-
ется инструментом, который использует архитектор системы для создания
"родного" машинного языка. Машинный язык сообщает аппаратуре, какую
конкретную команду следует выполнить.
В начале эволюции ЦП большинство наборов команд были аппаратно
кодированными. Это значит, что когда ЦП получал команду, декодирование
и выполнение производилось непосредственно цепями в кремниевой мик-
росхеме. Благодаря прогрессу в технологии ЦП, некоторые микросхемы мо-
гут быть программируемыми на уровне исполнения команд, что позволяет
конструкторам создавать и реализовывать новые наборы команд с мини-
мальными усилиями.
УРОВЕНЬ 2 - УСЛОВНАЯ МАШИНА
Данный уровень обеспечивает трансляцию из мнемоник языка ассемб-
лера в коды операций и данные машинного языка. Язык ассемблера - это
некоторая англо-подобная нотация, которая облегчает человеку понимание
и управление работой компьютеров.
Условная машина поддерживается ассемблером. Ассемблер может прев-
ращать идеи более высокого уровня в цепочки чисел, которые могут быть
затем выполнены. Наряду с ассемблером, применяются модели, помогающие
использовать аппаратуру компьютера. Здесь мы можем определить такие
вещи, как стеки, вектора прерываний и периферийный ввод-вывод.
Ядро является следующим логическим продвижением вверх и концепци-
ей, которую можно теперь реализовать программно на условной машине.
Ядро предоставляет среду, поддерживающую еще большие абстракции, чем
те, что рассматривались до сих пор. Двумя наиболее важными абстракция-
ми на уровне ядра являются управление процессами для мультипрограмми-
рования и многозадачности, и файловая система, которая управляет хра-
нением, форматом, поиском файлов и т.п. Когда эти две области перепле-
таются, мы имеем базовую функцию многопользовательской машины и ядро
операционной системы.
Одной из наиболее важных областей, которыми управляет ядро, явля-
ется безопасность. Проверки идентификации пользователя выполняются в
системных вызовах внутри ядра. Определенные механизмы используются яд-
ром для управления безопасностью файлов, устройств, памяти и про-
цессов. Единственный способ отключить механизмы безопасности состоит
в изменении исходного кода ядра и перекомпиляции всей системы, что
крайне нежелательно.
УРОВЕНЬ 4 - ОПЕРАЦИОННАЯ СИСТЕМА
Данный уровень строится на ядре, чтобы создать полную операцион-
ную среду. Потребность в дополнительных функциях системы можно удов-
летворить созданием автономных программ, имеющих конкретное назначе-
ние. Таким образом, совокупность всех специфических функций определяет
операционную систему.
Компилятор - это инструмент (или программа), построенный на опе-
рационной системе для дальнейшей разработки более совершенных и более
мощных сред. Новые среды могут предполагать еще большие абстракции,
чем на нижнем уровне, и делать больше допущений о том, что уже сущест-
вует. Это делает возможным символические конструкции более высокого
уровня, такие как структуры данных и управляющие структуры. Результа-
том является прикладная программа.
С помощью компилятора мы можем определить совершенно новый язык и
сделать его рабочим на компьютере, написав компилирующую программу,
которая читает этот новый язык. Это открывает целые новые области во
взаимодействии человека с машиной. Высокоуровневые языки могут вопло-
щать различные подходы к решению задач, например, процедурную модель
или объектно-ориентированную модель, и в конце концов, очевидно, могут
достичь выразительной мощи разговорного языка типа английского.
УРОВЕНЬ 6 - ПРИКЛАДНЫЕ ПРОГРАММЫ
В наше время прикладные программы могут означать массу разнооб-
разных вещей. Мы можем предположить, что любая программа, которая сде-
лана с помощью компилятора, является прикладной программой. Примерами
возможных прикладных программ являются следующее поколение языков, ин-
терпретаторов и генераторов прикладных программ. Интерпретатор - это
программа, написанная на распространенном языке высокого уровня, кото-
рая может декодировать и исполнять другой синтаксис (или язык). Приме-
ром, который интересует нас в системе UNIX, является командный про-
цессор shell. Это программа на языке Си, созданная для чтения и испол-
нения команд, записанных по правилам синтаксиса, определенных команд-
ным процессором shell.
Генератор прикладных программ - это программа, написанная на язы-
ке высокого уровня. Она предназначена для получения достаточной инфор-
мации от пользователя о его приложении и может использовать компиля-
торный язык, например Си, для написания прикладной программы, реализу-
ющей то, что требуется. Пользователь ничего не программирует. Выходом
генератора является рабочая программа.
UNIX не делает особых различий между уровнями. Некоторые особен-
ности системы, например, конвейеры, являются частью ядра на нижнем
уровне. Команда типа cat выполняет довольно простую функцию на уровне
операционной системы. Нечто подобное ls напоминает простую прикладную
программу с относительно малым набором опций. Большие программы, по-
добные семейству roff, определенно являются полновесными приложениями,
а средства типа sed и awk являются фактически интерпретаторами неболь-
ших языков программирования. Замечательной особенностью системы UNIX
является единообразие, которое она вносит в этот широкий диапазон
функций.
УРОВЕНЬ 7 - КОМАНДНЫЕ ФАЙЛЫ
Этот верхний уровень является языком, который интерпретирует
программа /bin/sh (в случае командного процессора Bourne shell). Ее
синтаксис поддерживает полный язык программирования. Хотя этот язык
лишен ряда встроенных структур и функций современного языка высокого
уровня, он имеет все необходимое для написания полезных программ.
Большим плюсом является то, что языку командного процессора доступны в
качестве внешних функций любые средства, утилиты и программы, которые
имеются в системе UNIX. Это значит, что алгоритмы, которые могут пот-
ребовать сто или более строк на языке низкого уровня типа Си, язык ко-
мандного процессора может выразить в двадцать строк. За счет потери
производительности, разумеется.
ВАШ "РЕГИСТРАЦИОННЫЙ КАТАЛОГ"
Поскольку UNIX создавалась как многопользовательская система,
многое сделано для того, чтобы система была безопасной и удобной для
каждого пользователя. Вам выделяется определенная часть файловой
системы (т.е. область на диске), которая является полностью вашей и
больше ничей. Вы можете заблокировать вашу область так, чтобы никто не
мог заглянуть вовнутрь, или же можете оставить ее открытой, чтобы дру-
гие люди могли читать эту область или писать в нее.
Помимо определения вашего места в системе, можно привязать "до-
машний" каталог (home-catalog) к вашим точным спецификациям. "Регист-
рационный каталог" - это не только область файловой памяти, но и вся
ваша среда. Можно установить переменные командного языка для определе-
ния путей по системе. Можно создать инструментарий, чтобы помочь вам в
работе.
Во многих более старых мини- и микрокомпьютерах среда имеет
"плоскую" файловую систему. Это значит, что все файлы размещаются в
одной огромной области хранения и нет логических разделов для их разг-
раничения. Отсутствие разделов порождает массу файлов, через которые
нужно пробраться, когда вы хотите найти определенный элемент. Некото-
рые системы имели в своих файловых системах групповые разделы, но
обычно такие разделы были различными плоскими файловыми системами.
Время показало, что такой тип среды (или модели) - не лучшее решение.
Решение, которое использует UNIX,- перевернутая модель дерева.
Корень системы находится наверху, а ветви растут в стороны и вниз.
Имеется один и только один корень наверху. Ветви могут исходить в лю-
бом направлении и простираться вниз на любую глубину. Кроме того, вы
можете иметь присоединяемые ветви, которые можно изъять из системы, а
затем вернуть обратно. Они монтируются на существующую в системе дре-
вовидную структуру.
Когда вы регистрируетесь в системе, вы можете попасть в любое
место древовидной структуры. Регистрационный каталог определяется в
файле паролей. К ней можно обратиться по имени $HOME, которая является
одной из предопределенных переменных командного языка для вашего
использования. Теперь у вас есть персональная древовидная структура
под этим именем каталога. Она полностью ваша и может быть сделана не-
доступной для кого угодно, кроме корня. Вы можете организовать ваш ре-
гистрационный каталог ($HOME) любым приемлемым для вас способом.
ПЛАНИРОВКА РЕГИСТРАЦИОННОГО КАТАЛОГА
Как только ваш регистрационный каталог присоединен к определенно-
му месту дерева, вы получаете полное управление структурой, которая
существует ниже этого места. Вы можете оставить ее плоской или сделать
подобной дереву. Эта структура зависит фактически от ваших потреб-
ностей и энтузиазма в эксплуатации вашей собственной области. Наиболь-
шая выгода для нас состоит в том, чтобы использовать вашу "домашнюю"
среду для поддержки ваших работ и максимально уменьшить объем ручной
работы. В следующих двух главах описано множество средств, которые мо-
гут работать с вашей личной файловой системой.
На рис.1-2 показана древовидная структура вашего регистрационно-
го каталога. Эта планировка представляет каркас среды, который вы мо-
жете заполнить соответствующей информацией.
По мере того, как растет ваше мастерство использования системы,
вам могут понадобиться эти типы областей для размещения в них информа-
ции. Вы обнаружите также, что наш сценарий хранения информации предпо-
лагает движение по деревьям, или их обход, так что вам гарантируется
выгода от использования иерархической конструкции.
Давайте пройдемся по этой примерной структуре и определим, каковы
ее части. Данная структура включает много файлов и каталогов, но все
они имеют определенное назначение. Возможно, вы не захотите использо-
вать в точности эти имена, но вы получаете совет, какие типы категорий
могут встретиться и как использовать систему для поддержки этой струк-
туры.
Корнем этого дерева является регистрационный каталог, который оп-
ределен в пятом поле файла /ets/passwd. Использование файла паролей
описано в passwd(4). Вот пример парольного входа автора:
russ:.pDIPADYfIXBY:103:101:Russ Sage:/usr/russ:/bin/sh
Слева направо вы видите имя пользователя (russ), пароль
(.pDI...), идентификатор пользователя (103), идентификатор группы
(101), личный комментарий, имя регистрационного каталога (/usr/russ) и
командный процессор shell, получаемый при входе в систему (/bin/ sh).
ФАЙЛЫ В РЕГИСТРАЦИОННОМ КАТАЛОГЕ
Файлы, описываемые ниже, разделяются на три категории: файлы, ко-
торые обычно присутствуют в вашей системе, если вы работаете в System
V, файлы, которые имеются обычно в Berkeley 4.2, и файлы, которые соз-
даются при использовании программ из настоящей книги.
Первый файл - это .news_time. Дата этого файла соответствует то-
му, когда вы последний раз читали новости в каталоге /usr/news. Для
чтения новостей пользуйтесь командой news(1). Эта команда выдает но-
вости, появившиеся позже даты создания файла .news_time.
Следующий файл - .profile. Этот файл выполняется при каждой ре-
гистрации в интерпретаторе shell и может быть использован для привязки
вашей собственной среды. В дальнейшем мы рассмотрим этот файл более
подробно.
Следующий файл - calendar (календарь). Этот файл содержит даты и
сообщения. Команда calendar(1) читает в этом файле даты, очень близкие
к текущей дате. Затем печатаются или посылаются вам по почте сообще-
ния.
Последний файл - mbox, ваш системный почтовый ящик. Когда вы с
помощью команды mail(1) сохраняете почту, она направляется по умолча-
нию в mbox.
Первым файлом здесь является .cshrc. Это первая стадия настройки
системы на пользователя, выполняемой интерпретатором cshell. В системе
UNIX присутствие "rc" в имени файла означает "команды запуска" ("run
commands") или "запуск при загрузке" ("run on boot up").
Файл .login является синонимом файла .profile интерпретатора sh.
Этот файл содержит команды настройки на среду пользователя, которая
вам нужна при регистрации в системе.
Следующий файл - .logout. Он выполняется, когда вы выходите из
системы. Например, вы можете применить его для печати учетной информа-
ции, такой как время, в течение которого вы работали в системе,
используемый вами размер дискового пространства и т.д. System V не
имеет подобного файла.
Следующий файл - .msgsrc, предназначенный для команды msgs(1)
системы Berkeley. Файл .msgsrc содержит последний, прочитанный вами
файл сообщений. Файлы сообщений хранятся в виде последовательно прону-
мерованных файлов в каталоге /usr/msgs.
Вот программы и файлы, которые вы можете разработать во время
использования данной книги. Файл .lastlog содержит даты каждого вхож-
дения в систему с вашими учетными данными. Программа, которая управля-
ет этим файлом, называется lastlog и представлена в главе 5.
Следующий файл - .trashcan. Это каталог, который временно хранит
файлы, удаленные вами. Если вы уверены, что они вам не нужны, то их
можно удалить навсегда. Эта особенность рассмотрена в главе 3.
Последний файл - .phone.list. Это ваша личная база данных со
списком телефонов. Она обслуживается командой phone (см. главу 5).
Первым каталогом является adm. Он содержит административные фай-
лы, которые вы можете иметь, например расписания, информацию о сотруд-
никах, встречах и т.д.
В каталоге bbs имеются подкаталоги для каждой "доски объявлений",
которую вы вызываете. Когда вы обращаетесь к этим системам, вы имеете
место для размещения всех соответствующих файлов и данных. Необходимая
вам информация - это меню для системы, вспомогательный текст, загрузки
программ и общая информация, которая вас интересует.
Каталог bin содержит все инструментальные средства, которые у вас
есть. Это могут быть командные файлы или объектные модули откомпилиро-
ванных программ. Подкаталог src не обязателен. В нем хранится исходный
код на языке Си для объектных модулей, имеющихся в bin, так что исход-
ный текст для быстрой фиксации ошибок и изменения всегда под рукой.
Каталог doc - это корень всех видов документации. Подкаталогами
здесь могут быть формы, письма, записки, разнообразная информация и
отчеты. Каждый подкаталог содержит определенные файлы в этих областях.
Каталог etc содержит любые системные или административные команды
и файлы, которыми вы пользуетесь. Если вы имеете административные обя-
занности, типичным содержимым этого каталога может быть резервная ко-
пия текущих конфигурационных файлов, используемых системой. Вы можете
сделать резервную копию файлов
/.profile
/etc/bcheckrc
brc
checklist
gettydefs
group
inittab
motd
mountable
unmountable
passwd
profile
rc
/usr/lib/crontab
/usr/lib/uucp/L.sys
USERFILE
uudemon.day
uudemon.hr
uudemon.wk
или любой другой информации о системе.
Каталог proj предназначен для специальных проектов, которые у вас
есть. Скорее всего, вы назовете этот каталог не proj, а по имени про-
екта, например, dev для разработки (development) или qa для чистовой
шлифовки (quality assurance). Все данные, корреспонденция, документа-
ция и исходный код для каждой работы направляются в главный каталог
проекта. Конечно, у вас может быть более одного каталога проекта.
Следующий каталог - mail. Это хорошее место для размещения вашей
почтовой корреспонденции от других людей, использующих систему. Имена
файлов в этом каталоге являются пользовательскими. Например, если бы я
получил почту от Боба, то она находилась бы в файле с именем bob.
Каталог src - для всего исходного кода. Логически сгруппируйте
ваш исходный код по подкаталогам, чтобы облегчить его поиск в будущем.
Возможными подкаталогами являются asm для ассемблерного кода, c для
исходного кода на Си, games (игры), misc (разное), script для команд-
ных файлов и sys для любого исходного кода, относящегося к системе.
(Если вы держите исходные тексты ваших личных инструментов в каталоге
/bin/src, то здесь вы, возможно, продублируете их.)
Каталог sys - это склад информации, имеющей отношение к системе.
Здесь могут быть резервные копии критических системных файлов, доку-
ментация по областям системы, куски выводимой информации команд who,
ps, uucp, регистрационных файлов или что-либо иное.
Последний каталог - tmp, который является рабочей областью для
размещения временных файлов. В основном все, что находится в tmp, вы
можете в любое время удалить, и средство can, описанное в главе 3, по-
могает вам в этом.
Отметим, что регистрационный каталог имеет минимальное количество
обычных файлов. Это уменьшает путаницу, которая может происходить с
плоскими файловыми системами. Каждый файл должен быть на своем месте,
но может быть размещен не только здесь. Если возникает какой-либо род
задач, когда файлы, связанные с этой задачей, могут быть перепутаны с
другими файлами, создайте отдельный каталог.
АНАЛИЗ ПРИМЕРА ФАЙЛА НАСТРОЙКИ СИСТЕМЫ
Файл .profile, как следует из его названия (профилирование - фор-
мирование контура, очертаний), функционирует для установки и инициали-
зации параметров системы, которые вам нужны. Сюда входит установка
терминалов, определение переменных, запуск программ и конфигурирование
исполняющей системы. Пример файла настройки можно найти в описании ко-
манды profile(4). Рассмотрим .profile, используемый автором. Мы вклю-
чили его на столь ранней стадии, чтобы предложить вам коснуться поня-
тий, которые более подробно раскрываются далее в этой книге. Не за-
ботьтесь о понимании работы каждой части примера. Пока что просто сде-
лайте мысленную отметку возможностей. Ваш .profile может быть проще и
почти наверняка будет другим.
1 # @(#).profile v1.0 Defines "home" on the system
Author: Russ Sage
3 CHOICE="ushort"
4 case $CHOICE in
5 ufull) PS1="`uuname -l`> ";;
6 ushort) PS1="`uuname -l|cut -c1-3`> ";;
7 graphic) PS1="^[[12mj^[[10m ";;
8 esac
10 LOGNAME=`logname`
11 HOME=`grep "^$LOGNAME:" /etc/passwd | cut -d: -f6`
12 MAIL=/usr/spool/mail/$LOGNAME
13 export LOGNAME HOME MAIL
15 HA=$HOME/adm
16 HBB=$HOME/bbs
17 HB=$HOME/bin
18 HD=$HOME/doc
19 HE=$HOME/etc
20 HM=$HOME/mail
21 HP=$HOME/proj
22 HSR=$HOME/src
23 HSY=$HOME/sys
24 HT=$HOME/tmp
25 HDIRS="HA HBB HB HD HE HM HP HSR HSY HT"
26 export $HDIRS HDIRS
28 P=/usr/spool/uucppublic/$LOGNAME; export P
30 CDPATH=.:..:$HOME:$HDIRS
31 PATH=.:/bin/:/usr/bin:/etc:$HOME/bin
32 SHELL=`grep "^$LOGNAME:" /etc/passwd|cut -d: -f7`
33 export CDPATH PATH SHELL
35 case "`basename \`tty\``" in
36 console) eval `tset -m ansi:ansi -m :\?ansi -r -s -Q`;;
37 tty00) eval `tset -m ansi:ansi -m :\?ansi -r -s -Q`;;
38 tty01) eval `tset -m ansi:ansi -m :\?ansi -r -s -Q`;;
38 esac
41 echo TERM = $TERM
42 TERMCAP=/etc/termcap
43 export TERM TERMCAP
45 HZ=20
46 TZ=PST8PDT
47 export HZ TZ
49 umask 0022
51 echo "\nTime of this login : `date`"
52 lastlog -l
54 RED="^[[31m"
55 GREEN="^[[32m"
56 YELLOW="^[[33m"
57 BLUE="^[[34m"
58 CYAN="^[[35m"
60 case "`date|cut -d' ' -f1`" in
61 Mon) echo "$RED";;
62 Tue) echo "$GREEN";;
63 Wed) echo "$YELLOW";;
64 Thu) echo "$BLUE";;
65 Fri) echo "$CYAN";;
66 esac
Когда вы входите в систему, регистрационная программа выполняет
интерпретатор shell с параметром '-' (например, -sh). Это сигнализиру-
ет интерпретатору shell, что сейчас момент регистрации и что должен
быть выполнен файл настройки. Сначала выполняется /etc/profile - общий
файл настройки, установленный системным администратором для всех поль-
зователей, а затем файл .profile пользователя. Каждый интерпретатор
shell после этого больше не запускает эти установочные программы. В
файле /etc/ profile интересно проверить машинно-зависимую информацию и
посмотреть, какие умолчания были для вас установлены. Если вы хотите
выполнить ваш .profile в любой момент после входа в систему, наберите
". .profile" (можно писать и ".profile", проверено, что обе формы ра-
ботают - Прим. переводчика).
Для поддержки вашего регистрационного каталога, используйте пере-
менные командного процессора (переменные shell), чтобы облегчить пе-
редвижение и сократить количество нажатий клавиш при работе с маршрут-
ными именами. Переменные shell всегда являются строками и, будучи один
раз определенными, не исчезают, пока вы не выйдете из системы.
При использовании переменные shell являются локальными для рабо-
тающего в данный момент интерпретатора shell. Их можно передать ин-
терпретаторам shell более глубокого уровня путем их "экспортирования".
Следовательно, если вы создаете новый командный процессор, все ваши
экспортированные переменные будут по-прежнему определены для этого ин-
терпретатора shell. Исчерпывающий список переменных shell, установлен-
ных по умолчанию и используемых системой, см. в приложении 1.
Отметим, что в нашем примере файла настройки для каждого подката-
лога первого уровня, который есть в нашем регистрационном каталоге, мы
также имеем переменные shell, связанные с именем этого подкаталога.
Таким образом, мы можем легко обращаться к различным областям нашего
регистрационного каталога.
ПОСТРОЧНЫЙ РАЗБОР ПРИМЕРА ФАЙЛА НАСТРОЙКИ
Строки 3-8 делают хитрую установку главной подсказки - переменной
PS1. В строке 3 инициализируется переменная, которая выбирает подсказ-
ку. Значение ushort жестко закодировано в файле, но вы всегда можете
запросить его или установить его в зависимости от файла.
Первой альтернативой является ufull, используемая для установки
подсказки в виде полного имени узла uucp в локальной системе. Вы выби-
раете такую подсказку, если используете несколько машин и для доступа
к одной машине применяете другую. Отличительная подсказка напоминает
вам, какой машиной вы пользуетесь. Отметим, что подсказка имеет одина-
ковое число символов и для короткой строки, и для длинной. Если же вам
нужно имя узла uucp, но не нужна длинная строка для подсказки, вы мо-
жете выбрать ushort, что дает первые три символа имени узла. Как пока-
зано в строке 6, имя получается применением команды uuname для получе-
ния локального имени узла (опция -l). Затем это имя пропускается через
команду cut, которая вырезает символы с первого по третий. Результат
присваивается переменной подсказки.
Последняя альтернатива для тех из вас, кто имеет графические сим-
волы. Назначение в строке 7 есть греческий символ. Его можно получить
применением специальных управляющих последовательностей, которые ука-
зывают терминалам отображение специальных символов. Символы ^[ явля-
ются визуальным представлением управляющего символа в программе vi. Вы
можете получить этот символ в программе vi, набрав control-v, а затем
ESC. Последовательность ESC[12m означает, что следующий символ будет
напечатан как графический. Символ j является вашей подсказкой и прев-
ращается в графический символ, который выдается на ваш экран. Исполь-
зуя различные символы алфавита, вы можете иметь в виде вашей подсказки
почти любой графический символ. ESC[10m возвращает ваш терминал в ре-
жим обычного текста, так что все символы, печатаемые после того, как
вы набрали ESC[10m, являются нормальными.
Если вы хотите сохранить вашу пользовательскую подсказку для всех
подчиненных интерпретаторов shell, экспортируйте ее. Иначе вы получите
$ для всех интерпретаторов shell нижнего уровня.
Строка 10 присваивает переменной LOGNAME выход команды
logname(1). Команда logname - это обычная команда системы UNIX, кото-
рая печатает ваше регистрационное имя из файла /etc/passwd. Обычно эта
переменная установлена для вас системой, но данный пример показывает,
как вы можете установить ее вручную.
Строка 11 инициализирует переменную HOME. Она тоже устанавлива-
ется для вас системой, но мы хотим показать, как делать эти вещи осоз-
нанно, а не по умолчанию. Сначала мы ищем в файле паролей запись,
соответствующую переменной LOGNAME. Мы ищем от начала строки имя, ко-
торое завершается символом :, чтобы убедиться, что найдено только кор-
ректное соответствие имени пользователя. Затем вся запись посылается
команде cut, которая вырезает шестое поле - регистрационный каталог.
Преимущество такой стратегии в том, что регистрационный каталог авто-
матически меняется, если меняется запись в файле /etc/passwd.
Строка 12 инициализирует переменную MAIL. Определяя MAIL, вы ука-
зываете, что вы должны быть уведомлены о посылке вам новой почты, если
вы находитесь в режиме on line. Строка 13 экспортирует эти переменные,
так что они доступны нам в порожденных интерпретаторах shell.
Строки 15-24 определяют все каталоги первого уровня в нашем ре-
гистрационном каталоге. Большинство имен состоят из двух букв, некото-
рые из трех. Теперь мы можем применять команды такого вида:
$ cd $HD
$ ls -R $HSR
$ cu -ltty00 dir | tee $HBB/board/session$$
Строка 25 присваивает переменной HDIRS все имена каталоговых пе-
ременных, что облегчает подключение всех каталогов без повторного вво-
да их имен. Мы можем просмотреть все каталоги и напечатать размер
используемого дискового пространства:
$ for DIR in $HDIRS
> do
> echo "disk usage for $DIR: `du -s $DIR`"
> done
Строка 26 экспортирует переменные так, чтобы мы могли всегда их
использовать. Отметим, что мы экспортировали $HDIRS и HDIRS. Перед
тем, как выполнить экспортирование, $HDIRS было распространено на все
различные имена переменных. Следовательно, фактически мы экспортирова-
ли все имена плюс саму переменную HDIRS.
Строка 28 инициализирует P так, чтобы это был ваш каталог в
PUBDIR, то есть /usr/spool/uucppublic. Теперь у нас есть простой
способ ссылаться на наши файлы при работе с командой uucp.
Строка 30 устанавливает CDPATH. Это путь, который проверяется,
когда вы выполняете команду cd. Сначала проверяется текущий каталог
(.) на предмет того, есть ли в нем имя каталога, в который вы хотите
попасть. Затем проверяется .. (родительский каталог). После этого
просматривается ваш регистрационный каталог. Последним назначением
CDPATH является $HDIRS, что подключает имена всех подкаталогов. Цель
этих имен - позволить команде cd искать в соответствующем каталоге
введенное вами имя.
Например, если бы вы были в /etc и набрали "cd doc", вы бы попали
в $HOME/doc, поскольку CDPATH содержало в себе $HOME. Аналогично, если
бы вы имели подкаталог $HOME/doc/status и ввели "cd status" откуда-ли-
бо из другого места в системе, вы бы пришли в $HOME/doc/status, так
как корень $HOME/doc был в CDPATH.
Порядок поиска в каталогах такой же, как объявлено в переменной
CDPATH. Если вы вводите имя каталога, которое встречается более чем в
одном месте, вы попадаете в первый каталог, обнаруженный при последо-
вательном поиске. Например, если бы вы сказали "cd sys", то попали бы
в $HOME/sys прежде, чем в $HOME/ src/sys.
В табл. 1-1 приведен пример эквивалентных команд cd, представлен-
ных в трех различных формах, которые понимает UNIX. То, какую форму вы
используете, зависит от того, что считается наиболее удобным и требует
как можно меньше нажатий клавиш.
Таблица 1-1
Три способа использования команды cd
Абсолютный CDPATH Относительно
переменной
cd /usr/russ cd cd $HOME
cd /usr/russ/src/asm cd asm cd $HSR/asm
cd /usr/russ/doc/paper/conf cd paper/conf cd $HD/paper/conf
cd /usr/russ/tmp cd tmp cd $HT
Строка 31 инициализирует переменную PATH. PATH работает таким же
образом, как CDPATH. Она ищет программы, которые нужно запустить, в
каждом каталоге, указанном в переменной PATH. Если имя не найдено ни в
одном из этих каталогов, печатается сообщение ": not found"
("<имя-файла>: не найдено").
Поскольку мы можем установить наш PATH как угодно, можно указать
все таинственные места в системе, в которых расположены исполняемые
модули. Когда мы хотим их выполнить, мы не обязаны их искать и наби-
рать полное маршрутное имя. Чтобы дополнить PATH, введите, например,
следующее:
PATH=$PATH:/usr/lib/uucp
Команда paths, представленная далее в этой книге, использует
$PATH, чтобы сообщить нам, в каком каталоге размещен исполняемый мо-
дуль.
Строка 32 инициализирует переменную SHELL. Эту переменную могут
использовать не более чем одна или две утилиты. Обычно она устанавли-
вается системой, когда вы регистрируетесь. Строка 33 экспортирует пе-
ременные CDPATH, PATH и SHELL.
Строки 35-39 - это хитрый способ установки определений термина-
лов. Строка 35 начинается со спрятанной команды tty, заключенной в
знаки ударения (`...`). Выходом команды tty является "/dev/tty00". За-
тем мы берем основное имя этой строки, т.е. "tty00". Далее мы исполь-
зуем структуру переключателя по этому значению, чтобы увидеть, что мы
хотим сделать для каждого конкретного терминала. Команды tset, пока-
занные здесь, относятся к среде XENIX и могут быть неприемлемыми в ва-
шей среде.
Строка 41 делает эхо-отображение значения TERM на экран, чтобы
сообщить вам тип вашего терминала, если он вам нужен. Это значение
доступно, если описанная ранее команда tset устанавливает для вас TERM
как часть своей обычной работы.
В строке 42 устанавливается переменная TERMCAP, указывающая на
/etc/termcap. Это обычный способ установки переменной TERMCAP. Другой
способ - присвоить TERMCAP текущую закодированную строку, которая на-
ходится в файле описания терминала. Если TERMCAP установлен на закоди-
рованную строку, то утилите vi нет необходимости обращаться к файлово-
му вводу-выводу, чтобы получить характеристики вашего терминала. Стро-
ка 43 экспортирует эти значения так, чтобы они были доступны на любом
уровне интерпретатора shell.
Строка 45 устанавливает частотную переменную. Это переменная из
XENIX и, возможно, имеется в System V. Она используется для установки
информации о времени.
Строка 46 устанавливает информацию о зоне времени, как это требу-
ется в библиотечном вызове ctime(3). Имея переменную TZ, вы можете пе-
рекрыть подразумеваемую зону времени при доступе ко времени из прог-
раммы на языке Си. Строка 47 экспортирует эти переменные.
Строка 49 устанавливает ваше значение маски пользователя (umask).
Она управляет подразумеваемым разрешением доступа для всех файлов, ко-
торые вы создаете. Система вычитает значение umask из 777. Результат
становится правом доступа к файлу, в данном случае 755. Когда вы соз-
даете каталог с правом доступа 755, этот каталог показывается командой
"ls -l" как rwxr-xr-x. Когда вы создаете некаталоговый файл с правом
доступа 755, этот файл показывается как rw-r--r--, что эквивалентно
644. Некаталоговые файлы не имеют бита x, поэтому их нельзя исполнить.
Каталогам же нужен установленный бит x, чтобы они были доступны по ко-
манде cd.
Строки 51 и 52 сообщают вам о времени вашего сеанса работы в
системе. Строка 51 сообщает вам текущее время вашего входа в систему,
а строка 52 вызывает программу lastlog, которая печатает дату вашей
последней регистрации в системе. Программа lastlog описана в главе 5.
Строки 54-58 инициализируют переменные, генерирующие цвета на
цветном мониторе. Управляющие значения являются стандартными значения-
ми кодов ANSI. Это работает в системе XENIX и может работать в вашей
системе. Растровая графика не доступна, но имеется символьная графика
и различные основные (foreground) и фоновые (background) цвета. Основ-
ные цвета кодируются числами, начиная с 30, а фоновые цвета - числами
с 40.
Строки 60-66 - просто для забавы. Они представляют собой хитрый
способ устанавливать каждый день на экране различные цвета. Строка 60
начинается с запуска команды date и передачи ее выхода по конвейеру
команде cut. Вырезается первое поле, которое является днем недели. За-
тем мы создаем структуру переключателя по строке дня, выполняя различ-
ные действия для каждого дня. Благодаря эхо-отображению управляющих
последовательностей, монитор реагирует немедленно.
ТЕОРИЯ ОТНОСИТЕЛЬНОСТИ ВНУТРИ СИСТЕМЫ UNIX
Теперь, когда мы ознакомились с "домашней" средой, следующий шаг
- обратиться к средам, находящимся вне регистрационного каталога
($HOME). Например, что представляют собой другие каталоги на том же
уровне, что ваш $HOME ? Кто еще работает в системе? Как попроще полу-
чить доступ к их каталогам? Можете ли вы запускать программы в чужих
каталогах? Такого рода вопросы и действия относятся к другим людям в
вашей системе.
Единственный способ ответить на эти вопросы - посмотреть вокруг
себя. Никто не собирается рассказывать вам, что такое система. Вы
должны сами исследовать ее и выяснить, куда вы можете ходить, а куда
нет. Система конечна, так что вы можете себе помочь, делая распечатки
всех каталогов и файлов.
Вы можете маневрировать в системе UNIX, используя относительную
нотацию. Поскольку системное дерево образовано из каталогов, обозначе-
ния . и .. позволяют нам двигаться вверх и вниз по дереву. В любой
точке .. означает родительский каталог текущего каталога, в котором мы
находимся.
Ниже показаны некоторые примеры относительных команд.
ls -l $HOME/.. перечисляет файлы в моем родительском
каталоге.
cd ../../.. в предположении, что текущим каталогом
является /usr/russ/src/c, делает моим
текущим каталогом /usr.
ls . перечисляет файлы в текущем каталоге.
ls .. перечисляет файлы в моем родительском
каталоге.
$HOME/../../bin/ls запускает ls в каталоге
/usr/russ/../../bin, т.е. в /bin/ls.
../fred/bin/ls запускает команду ls в каталоге
двоичных модулей Фреда, который имеет
тот же родительский каталог, что и я,
т.е. /usr/fred/bin/ls.
Системная среда не просто НАХОДИТСЯ в системе UNIX, а ЯВЛЯЕТСЯ
системой UNIX. Как мы увидим в этой книге, вся система - UNIX, Си, ко-
манды, файлы и т.д. - это просто логический подход к функционированию
компьютера. Программное обеспечение - это то, что определяет система
для конечного пользователя. Мы можем представлять все машины, работаю-
щие в системе UNIX, как одинаковые и трактовать каждый UNIX как один и
тот же. Мы предполагаем, что реакция машины будет каждый раз одинако-
вой.
Мы можем смотреть на UNIX таким же образом, как на физические за-
коны. Мы ограничены ими, но мы также вольны применять эти законы в си-
туациях и областях, с которыми мы до этого никогда не встречались. Мы
можем доверять этим законам и допускать, что они применимы везде, куда
бы мы ни направились. Такова система UNIX, по крайней мере в идеале.
Система имеет много сред. Важно понимать, что они собой представ-
ляют, как взаимодействуют и для чего могут быть использованы. Так же,
как
программы = структуры данных + алгоритмы
так и
UNIX = файловое дерево + утилиты
Среда UNIX - это сочетание двух важнейших вещей: файлового дерева
и интерфейса системных вызовов. Это дерево допускает бесконечное
расширение возможностей, позволяя монтировать внешние дисковые области
в любой точке файловой системы. Дерево помогает также в сборе логи-
чески связанных файлов, что делает систему более организованной.
Интерфейс системных вызовов обеспечивает набор инструментов, из
которых можно построить большинство других функций. Определение интер-
фейса System V имеется в виде типографской книги и может быть найдено
в книжных магазинах. Строгое следование этому стандарту гарантирует
совместимость с постоянно развивающейся AT&T System V.
Для того чтобы лучше понять мир UNIX, посмотрите пример распечат-
ки структуры UNIX на рис.1-3 . Это наглядное представление полного де-
рева корневой файловой системы. Любые другие расширения файловой
системы монтируются на эту файловую систему.
Точкой временного монтирования является /mnt. Более постоянные точки
монтирования должны быть созданы администратором, например /0, /1 и
т.д. или /usr1, /usr2 и т.д.
Самым левым каталогом является /bin, который содержит все главные
двоичные утилиты. Это наибольший из двух основных каталогов двоичных
модулей.
Следующий каталог - /dev, в котором размещены все файлы уст-
ройств. Файлы устройств являются точками доступа к периферии, подсое-
диненной к системе. Этот файл привязан к периферии с помощью ядра и
драйвера устройства.
Административные утилиты и конфигурационные файлы хранятся в
/etc. Примерами являются getty и gettydef, init и inittab, а также
файл паролей (/etc/passwd).
Следующий каталог - /lib, где размещены библиотеки компилятора.
Здесь могут храниться и другие типы библиотек.
Каталог /lost+found используется утилитой fsck (главное средство
поддержания файловой системы) для хранения логически удаленных файлов.
Если на самом деле вы хотите сохранить эти файлы, они могут быть изв-
лечены из этой удерживающей области после завершения уборки файловой
системы.
Следующий каталог - /mnt. Это временная точка монтирования для
файловых систем. Мы часто монтируем и демонтируем файловые системы
просто для того, чтобы запустить быструю проверку чего-либо. Здесь под-
ходящее место для этого.
Главным временным рабочим каталогом системы является /tmp. Многие
утилиты, такие как vi, fsck, интерпретаторы shell и программы резерв-
ного копирования, используют /tmp для хранения рабочих файлов.
Следующий каталог - /usr, который применяется как точка монтиро-
вания. Файловая система, смонтированная здесь, содержит дополнительную
системную информацию и каталоги пользователей. Это разделение между
загружаемой файловой системой и пользовательской файловой системой бы-
ло сделано, чтобы сбалансировать загрузку диска. Если бы все важные
файлы были в одном разделе, он был бы слишком большим. Производитель-
ность может быть ухудшена, если все действия направлены в одну логи-
ческую область диска. Благодаря разбивке всей системы на две, каждая
файловая система поддерживает разумное количество свободного прост-
ранства. Чуть ниже мы рассмотрим каталог /usr более подробно.
Последний файл - это само ядро, /unix. Весь /unix фактически су-
ществует и представляет собой большой a.out (скомпилированный объект-
ный файл). Ядро изготавливается путем запуска ld на группе библиотек,
которые загружаются по очереди в огромный исполняемый модуль, называе-
мый /unix. Машина запускается с первых 512 байтов корневой файловой
системы. Программа начальной загрузки, которая находится здесь, загру-
жает программу загрузки большего размера, иногда называемую /boot.
/boot загружает и запускает /unix.
Второй слой каталогов размещается под /usr. Как упоминалось ра-
нее, /usr используется как точка монтирования для другой файловой
системы. Это значит, что все файлы, которые имеются в /usr, находятся
в другом разделе загружаемого диска или вообще на другом диске.
Первым каталогом является adm, для администрирования. Он
содержит учетные файлы и регистрационный файл для su (супер-
пользователя), а также другие административные файлы.
В каталоге bin имеются исполняемые модули, которые используются
менее часто, чем модули в двоичном каталоге корневого уровня (/bin).
Почти все исполняемые модули распределены между этими двумя каталога-
ми. Другие исполняемые модули рассеяны по всей системе, например
/usr/lib/uucp/uucico и /usr/lib/ ex3.7preserve.
Далее games. UNIX приходит с ассортиментом интересных игр. Боль-
шинство из них текстовые, но предоставляется несколько программ графи-
ческого типа, например worm, worms и rain.
Каталог include содержит все файлы-заголовки. Файлы-заголовки
используются в программах на языке Си для определения структур и
системных присваиваний, полезных для программирования. Здесь имеется
подкаталог sys, который содержит все файлы= заголовки, относящиеся к
системе. Читая эти файлы-заголовки, можно многое узнать о системе
UNIX.
Следующий каталог - lib, который содержит библиотечные файлы для
всех видов "имущества": файлы печатающих устройств, файлы поддержки
утилиты vi, другие языки и uucp. Каталог /usr/ lib представляется
складом всяких библиотек, которые имеются в системе, отличных от биб-
лиотек компилятора.
Каталог lost+found находится здесь для той же цели, что и однои-
менный каталог корневого уровня. Каждая файловая система должна иметь
такой файл. Без него fsck не имеет временного места для размещения по-
луудаленных файлов и поэтому удаляет их навсегда.
В каталоге mail находится ваш системный почтовый ящик. Когда вы
запускаете команду mail, здесь накапливается очередь сообщений. В ка-
талоге usr/mail каждый файл носит имя пользователя. В этом файле хра-
нится почта пользователя, пока он не прочитает ее.
Каталог man предназначен для активных страниц руководств по
системе UNIX. Наличие постоянного доступа к страницам руководств явля-
ется хорошим средством. Однако, эти страницы занимают много места, и
доступ к ним может потребовать довольно много времени при сильно заг-
руженной системе.
В каталоге news хранятся все файлы новостей. Эти файлы именованы
в соответствии с порядком, в котором они были введены в каталог. Ко-
манда news(1) смотрит на дату файла $HOME/ .news_time, чтобы сообщить,
какие новости вы еще не читали.
Каталог preserve предназначен для файлов, связанных с утилитой
vi. Они помещаются сюда, когда вы работаете с vi или с редактором ex и
пропадает питание машины либо ваш сеанс работы прерывается в виде "за-
висания". Когда в системе восстанавливается питание, /tmp содержит
файлы редактора ex. Из каталога /etc/rc запускается утилита
/usr/lib/ex3.7preserve, которая просматривает /tmp, преобразует его в
сохраненный файл и помещает его в /usr/preserve. Когда вы входите в
систему, вы получаете почту о том, что у вас имеется сохраненный файл
редактора, который вы можете восстановить и поместить его на исходное
место.
Каталог pub не содержит ничего особенного, обычно в нем просто
некоторые информационные файлы вроде таблицы ASCII или греческих сим-
волов.
Каталог spool - это главная точка входа для всех буферизованных
файлов в системе. В этом каталоге имеется много подкаталогов, содержа-
щих специфические типы буферизованных файлов. Некоторыми типичными
подкаталогами являются lp, uucp и uucppublic.
В каталоге src хранится исходный код системы UNIX, если он име-
ется в системе. От этого каталога ответвляется много уровней: команды,
библиотеки, код ядра, код машинного языка и автономные утилиты. Часто
в /usr/src хранится также исходный код для локальной машины.
Каталог sys традиционно хранит файлы, необходимые для генерации
нового ядра. Это файлы-заголовки, конфигурационный файл, библиотеки и
командный файл для создания нового ядра из всех этих файлов.
Последний каталог - tmp. Это вторичная временная область хране-
ния, которая используется не так часто, как /tmp. Ее, однако, исполь-
зует утилита sort.
ЖИЗНЬ СИСТЕМЫ UNIX: НЕКОТОРЫЕ МЕТАФОРЫ
UNIX - это особый мир, живущий своей жизнью. Его социальная
структура имитирует реальную жизнь, с правительством, содержащим пра-
вителя (корень root), штатом поддержки (bin, cron, lp, sys) и массами
(/usr/*). Массы не имеют доступа к мощи правителя, если не используют
предварительно установленных средств (/bin/su) или не занимаются кри-
минальными действиями и нарушением мер безопасности. Как и в любом об-
ществе, большая многопользовательская система UNIX устанавливает права
и обязанности своих пользователей.
При входе в систему пользователь получает свое "место под солн-
цем" (регистрационный каталог - $HOME ). Это место зависит от того,
что было раньше (от родительского каталога ..), а будущие места за-
висят от того, что происходит позже (каталоги, подчиненные $HOME).
Работа распределяется по организациям и иерархиям в зависимости
от их функций в обществе (все пользователи в /usr, все транзитные фай-
лы в /usr/spool, все функции безопасности в /etc). Посмотрите вокруг
себя в вашей системе, чтобы ознакомиться с вашим миром. Вы можете
после этого выбрать, участвовать ли в некоторой части этого мира или
игнорировать ее.
Движение людей в системе UNIX происходит параллельно. Некоторые
области (/tmp) доступны всем, а некоторые области сильно охраняются от
большинства людей (/etc/passwd). Транспортная служба может перевезти
наши вещи (передача файлов по сетям uucp). Мы даже можем воспользо-
ваться общественным транспортом, чтобы добраться в разные части города
(вход в другие системы (rlogin), эта особенность имеется только в
BSD).
В мире UNIX нам доступны различные пути. Эти пути помогают нам
сформировать свою судьбу (дисковые разделы, монтированные в любое
место файлового дерева). Когда дисковый пакет монтируется, он стано-
вится доступным нам. Когда он демонтируется, мы теряем доступ к нему.
Когда запускаются процессы, они проходят через различные этапы
своей жизни. Они рождаются (ответвляются), растут (становятся планиру-
емыми и помещаются в таблицу процессов) и, наконец, становятся произ-
водительными рабочими в обществе (переходят в состояние запуска и вы-
полняются).
Все процессы имеют фамильное дерево. Порожденный процесс всегда
имеет родителя, а родительские процессы могут порождать много "детей".
В зависимости от приложения, они могут быть "дедами" и "внуками". Про-
цессы "умирают" так же легко, как создаются. Одной из необычных вещей
в мире UNIX является то, что "дети" почти всегда "умирают" раньше сво-
их "родителей".
Правительство (ядро) проводит в жизнь параметры среды, которые
выглядели бы в довольно тоталитарном духе, если бы это было в реальном
мире. Только определенное число рабочих допускается к рабочему месту
одновременно (это максимальное количество ячеек в таблице процессов).
Рабочие ограничены в числе "детей", которых они могут иметь (макси-
мальное количество процессов на пользователя). Поскольку рабочие на-
капливают материальные ценности, они ограничены в количестве товаров,
которые они могут поместить в комнаты своих домов (максимальный размер
файла, или ulimit). Хотя не установлен лимит на число различных файлов
(комнат) максимального размера, которые могут существовать, вся систе-
ма имеет предел (df показывает свободное пространство), и одна не-
насытная персона может нанести удар по окружающим. Здесь возникает
своего рода экология.
Так же, как компьютерный век проходит под присмотром электронной
автоматики, так и UNIX ведет таблицы о деятельности всех пользовате-
лей. Механизмы учета организованы правительством (внутри ядра) и всег-
да записывают действия каждого пользователя. Тем не менее, это свобод-
ное общество в той мере, что вы можете получить распечатку о вашем
кредитном состоянии (используя acctcom для печати учетных записей).
Хотя система UNIX имеет негативные аспекты (как и человеческое
общество), в ней есть также некоторые очень позитивные особенности.
Гибкость системы и богатство инструментов дает нам очень продуктивную
и детально разработанную рабочую среду. Наша производительность в этом
смысле ограничена в основном нашим собственным воображением. Когда ра-
бота становится слишком утомительной и скучной, мы всегда можем создать
средства, делающие за нас эту работу. Это обстановка свободной инициа-
тивы, в которой хорошие идеи могут дать значительное увеличение произ-
водительности.
Непрерывное снижение цен, рост производительности в наше время и
ожидаемое появление новых микро- и супер-микрокомпьютеров делают мощь
системы UNIX доступной для все большего круга пользователей. Системы
UNIX или типа UNIX работают на любых машинах, от уровня PC-XT до AT и
выше. Доступность больших объемов оперативной памяти и мощных микроп-
роцессоров привела к возрастанию интереса к многозадачности, системам
мультипроцессирования - сфере, в которой UNIX имеет солидную репута-
цию.
Однако применение UNIX с максимальной отдачей - дело нелегкое.
Люди годами высказывали неудовлетворение тем, что она не является
"дружественной" по отношению к пользователю - и это разумная критика,
хотя на самом деле UNIX содержит средства для построения интерфейсов
любого требуемого уровня сложности. Наиболее важная причина трудоем-
кости эффективного использования UNIX состоит в том, что в системе
используются очень плодотворные идеи, не знакомые многим людям, рабо-
тавшим с более простыми операционными системами. UNIX предоставляет
также гораздо больше инструментальных средств, более гибких и с су-
щественно большими возможностями, чем, например, популярная MS-DOS (в
чем можно убедиться беглым сравнением соответствующих руководств).
Вероятно, Вы, читатель, начинали с изучения UNIX в объеме, доста-
точном для решения конкретных задач в вашей системе, будь то текстовая
обработка и форматирование текстов, программирование или запуск ста-
тистических пакетов. Через некоторое время вы, видимо, накопили (от
других людей или в результате собственной работы) небольшой набор при-
емов, включающий, возможно, некоторый опыт простого программирования
для интерпретатора командного процессора.
Хотя это естественный путь развития, принимая во внимание, что в
UNIX более 200 команд, вы можете не заметить или пропустить многие
мощные и полезные идеи. Более важно то, что вы можете лишиться
перспективного взгляда, который приходит с полным пониманием того, как
работают различные части UNIX, и концепций, которые лежат в их основе.
В книге показаны многие полезные инструментальные средства и при-
емы, которые вы можете сразу применять в работе, чтобы значительно по-
высить производительность UNIX. В отличие от некоторых книг, которые
просто представляют набор командных файлов или других средств, здесь
описываются подробности того, как работает каждая программа, и указы-
ваются некоторые направления адаптации программ для ваших конкретных
нужд. Сочетание инструментальных средств, концепций и техники решения
задач поможет вам стать мастером UNIX.
Для того, чтобы извлечь пользу из данной книги, вы должны обла-
дать некоторым базовым опытом работы в системе UNIX. Вы должны знать
общие аспекты файловой системы, такие, как каталоги, вложенность и
маршрутные имена. Вы должны знать, как использовать один из редакторов
UNIX, чтобы вводить командные файлы интерпретатора командного про-
цессора и, по крайней мере, слегка знать программирование с использо-
ванием командного процессора. Мы сделали мало допущений, касающихся
того, что вы должны знать о данной команде или особенностях UNIX. Каж-
дая команда или понятие объясняется, когда оно вводится, а периоди-
ческие экскурсы в ваши руководства по UNIX могут прояснить все темные
места. Запомните одно: имеется так много команд с таким большим коли-
чеством опций, что даже мы, профессионалы, должны время от времени об-
ращаться к книге.
Если вы только начинаете использовать UNIX, то книга "UNIX Primer
Plus" ("Расширенный букварь по UNIX") Митчела Уэйта (Mitchell Waite),
Дональда Мартина (Donald Martin) и Стефена Прата (Stephen Prata)
(SAMS, 1983) даст вам исчерпывающее введение в предмет. Если вы уже не
новичок, но все еще не имеете четкого представления о внутренней рабо-
те командного процессора и программировании для него, то вам даст фун-
даментальные основы другая книга - "Advanced UNIX - A Programmer's
Guide" ("Руководство программиста по расширенному UNIX") Стефена Прата
(SAMS, 1985). Фактически эта книга является идеальным спутником и
справочником для дополнительных исследований, которые составляют нашу
книгу.
О КАКОЙ СИСТЕМЕ UNIX ИДЕТ РЕЧЬ
Имеется, конечно, много вариантов UNIX. Помимо основных семейств
реализаций UNIX (AT&T System V, Microsoft XENIX и Berkeley [BSD]),
распространено несколько различных командных процессоров, среди кото-
рых наиболее широко используются два - командный процессор Bourne ко-
мандный процессор Си. Все командные файлы в данной книге были провере-
ны и в System V, и в XENIX с использованием командного процессора
Bourne, за исключением тех случаев, которые специально отмечены. БОЛЬ-
ШИНСТВО наших командных файлов работает также под управлением команд-
ный процессор Bourne в BSD, хотя нескольких команд System V нет в
системе BSD и наоборот. Мы пытались указать те места, в которых эти
две системы существенно отличаются, и дать некоторые альтернативные
подходы для пользователей BSD.
Большинство наших командных файлов было также переписано для за-
пуска под управлением программного процессора Си после учета син-
таксических отличий. Если вы пользуетесь командным процессором Bourne
и хотели бы поэкспериментировать с программным процессором Си, то хо-
рошим введением является указанная ранее книга "Advanced UNIX - A
Programmer's Guide".
Если один из наших командных файлов не работает в вашей системе,
не впадайте в панику. Проверьте, пожалуйста, следующее:
- Какая у вас версия UNIX? Отмечали ли мы что-нибудь относительно
этой версии?
- Какой командный процессор вы используете (Bourne, Си или дру-
гой)?
- Должны ли вы поменять маршрутное имя в силу того, что в вашей
системе что-то находится в другой части?
- Не утратили ли вы прав доступа к определенному файлу? Не нужно
ли вам применить команду su, чтобы получить другой идентифика-
тор пользователя или стать в корень?
- Использует ли данный командный файл предварительно под-
готовленный командный файл, который вы еще не ввели в
вашу систему?
Большинство из этих советов довольно очевидны, но никогда не ме-
шает сделать глубокий вдох и внимательно подумать, прежде чем нырять в
отладочные сеансы.
Давайте бросим беглый взгляд на то, что описывается в данной кни-
ге, чтобы вы получили представление о предмете книги и знали, где най-
ти нужную тему.
Глава 1 - введение в среду выполнения системы UNIX в целом,
способы обращения пользователей к ее различным частям. Вы увидите, ка-
ким образом ваш рост как мастера UNIX позволит вам максимально успешно
применять все аспекты и особенности среды.
В главе 2 рассматривается наиболее важная особенность среды UNIX
- файловая система - и вводятся инструментальные средства для изучения
файловых структур и содержимого файлов.
Глава 3 предоставляет средства для практических каждодневных за-
дач по сопровождению файлов - для копирования и сохранения файлов и
для удаления ненужных файлов.
В главе 4 описываются виды файлов, которые важны для программной
документации, и предоставляются инструментальные средства, которые об-
легчают вам сопровождение вашей растущей коллекции программных
средств.
В главе 5 обращено внимание на вашу собственную среду (home-сре-
ду) и личное администрирование. Сюда относится управление вашим плани-
рованием и задачами. Представлено несколько полезных средств, помогаю-
щих вам.
Глава 6 предоставляет способы получения сведений о других пользо-
вателях и средства для обеспечения безопасности вашего рабочего прост-
ранства в системе.
В главе 7 рассматриваются некоторые аппаратные части устройств
UNIX, особенно, терминалы и диски с некоторыми примерами инструмен-
тальных программных средств. Включены также инструменты для работы с
файловыми системами.
Глава 8 посвящена коммуникациям в UNIX - сфере, значимость кото-
рой быстро возрастает. Этот материал поможет вам работать с несогласо-
ванными модемами, а также с проблемами безопасности и управления, ко-
торые возникают при работе с командами cu и uucp. Предлагаемые
средства помогут вам в работе как с коммуникациями от UNIX к другой
операционной системе, так и от UNIX к UNIX. Приведены также практи-
ческие примеры аппаратных конфигураций.
Глава 9 вводит читателя в системное администрирование и безо-
пасность. Вы можете найти здесь информацию, которую вы могли бы полу-
чать самостоятельно только посредством многолетнего чтения и экспери-
ментирования. Поскольку UNIX становится более распространенным в "ре-
альном мире", безопасность становится очень важным вопросом. Мы
представляем концепции, даем информацию о том, за чем необходимо сле-
дить, и инструментальные средства, помогающие следить.
Глава 10 завершает книгу подборкой специальных приемов UNIX,
включающих одну-две командные строки, которые действуют неожиданно эф-
фективно.
Набор приложений предоставляет информацию, полезную при програм-
мировании с помощью командного процессора и при отладке.
Поскольку некоторые из инструментальных средств используют ко-
мандные файлы, введенные ранее в данной книге, вы должны работать над
книгой в соответствии с последовательностью глав, когда внедряете ко-
мандные файлы в вашу систему. Однако