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

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

Содержание


Формат вызова
Текст программы
Переменные среды выполнения
Подобный материал:
1   2   3   4   5   6   7   8   9   ...   45

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 отработали успешно, кодом возврата явля-