Рассел Сейдж. Приемы профессиональной работы в unix перевод "Tricks of the unix masters" by Russel G

Вид материалаДокументы

Содержание


Возможные модификации
Формат вызова
Текст программы
Переменные среды выполнения
Управление выводными файлами больших размеров
Подобный материал:
1   ...   6   7   8   9   10   11   12   13   ...   45

После того как все аргументы проверены, мы в строке 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 могут передавать значения только вниз, порожденным процессам, но

процессы-потомки не могут передавать значения переменных вверх, роди-

тельскому процессу. Обычно передача значений переменных поддерживается

при помощи какого-либо файла, в котором хранятся данные для обмена

между родительским процессом и процессом-потомком.


УПРАВЛЕНИЕ ВЫВОДНЫМИ ФАЙЛАМИ БОЛЬШИХ РАЗМЕРОВ