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

Вид материалаДокументы
Подобный материал:
1   ...   12   13   14   15   16   17   18   19   ...   45


В строках 4-7 производится проверка на наличие ошибок условий вы-

полнения. Единственная ошибка условий выполнения - это когда вы указали

какие-либо аргументы cpiobr. Поскольку это управляемая с помощью меню

утилита, никаких аргументов передавать не нужно.

Для того, чтобы получить общее представление о том, как эта утили-

та работает, давайте подумаем над тем, что необходимо сделать. Во-пер-

вых, мы должны определить, какое действие должно быть выполнено. Полу-

чив эту информацию, нам необходимо узнать, какое устройство должно

использоваться. Что, если пользователь введет неверный выбор? Нам необ-

ходимо ожидать в цикле до тех пор, пока не будет введено правильное

значение.

После получения этих двух порций информации, нам нужно определить,

где искать или куда помещать файлы. После этого мы можем выполнять

cpio.

Для выполнения этого сценария нам нужно всего два цикла: по одному

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

"вечный цикл while". Для выхода из циклов мы используем команду команд-

ного процессора break, которая выводит нас из текущего цикла. Немного

позже мы увидим наличие проблемы при таком подходе.

Основной, самый внешний управляющий цикл начинается со строки 6 и

заканчивается в последней строке программы - строке 87. Целью этого

внешнего цикла является управление выполнением программы в целом, полу-

чение опций меню от пользователя и окончательный выход, когда пользова-

тель сообщает, что он закончил работу. Конечно, вы можете по-прежнему

выйти из программы при помощи обычного символа прерывания, но само меню

имеет ключ выхода (CR). Гораздо лучше представлять явный ключ, особенно

для неопытных пользователей.

Начиная со строки 11, мы устанавливаем экран для главного меню.

Командой здесь является "c", что будет пояснено позже в этой книге. Она

соответствует "очистке экрана" и может быть заменена стандартной коман-

дой очистки системы UNIX, которую вы можете использовать в этом месте,

если хотите.

Строка 12 устанавливает в позиционные параметры выходные данные

команды date системы UNIX. Такой синтаксис достаточно редко встреча-

ется, но тем не менее очень полезен. Если бы мы не хотели делать это

таким образом, мы бы должны были перехватить все выходные данные коман-

ды date в одной переменной, затем разделить их на мелкие порции и по-

местить каждую порцию в отдельную переменную. Это потребовало бы намно-

го больше команд и переменных в программе. Используя наш синтаксис, мы

заставляем первый позиционный параметр быть первым полем выходных дан-

ных команды date, второй позиционный параметр быть вторым полем и так

далее. Для получения любого указанного поля мы используем запись вида

$n, где n есть номер позиционного параметра.

Строки 13-25 - это один огромный оператор echo, который печатает

главное меню. Выдача всего необходимого одним оператором echo предпоч-

тительнее, поскольку это минимизирует накладные расходы, с которыми

приходится сталкиваться при выполнении большого числа операторов. Такой

путь быстрее. Если бы мы использовали оператор echo для каждой строки

главного меню, то оно печаталось бы очень медленно и прерывисто. Коман-

да UNIX cat также могла бы быть применена для этого случая, используя

здесь документы (вставленный текст). В качестве примера этого может

служить следующее:

cat <<-EOF

Main Menu Information

EOF


Однако главная проблема возникает, когда вы печатаете приглашение.

Для того, чтобы курсор ожидал ввода в конце строки приглашения, необхо-

димо выдать на терминал символ "\c", а cat не может сделать этого. Вы

выводите на экран меню с помощью cat, и echo печатает приглашение, ко-

торое направляется на другую сдвинутую строку полностью заполненного

экрана. Постоянство и скорость - вот чего мы добиваемся. Обучение таким

трюкам еще больше поможет вам при написании программ большого размера,

которые используют множество меню и другие текстовые выводы на экран.

Использование оператора echo в таком виде имеет некоторые не-

достатки, но они совершенно тривиальные. Во-первых, тело оператора echo

должно содержать все, что вы хотите вывести на экран, и это требует

абсолютного позиционирования внутри оператора echo для получения симво-

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

сдвиг строк в тексте программы, поэтому визуально в том месте командно-

го файла, где выводится меню, появляется этот сдвиг, но после меню

строки снова идут ровно. Это может немного смущать при чтении текста

программы.

Другой несущественной деталью является то, что оператор echo не

любит выводить символы табуляции. Если же вы вставили символ табуляции

внутри кавычек оператора echo, он обычно выводится как пробел. Для то-

го, чтобы заставить echo выводить символы табуляции, вы должны сказать

это оператору echo на его собственном языке с помощью символов "\t" или

\\t, если без кавычек. Поэтому меню в cpiobr заполнено символами пробе-

ла. Это также позволяет легко сдвигать меню влево и вправо при помощи

небольшого количества пробелов для соответствующего позиционирования на

экране.

Одним из спорных вопросов является место, где меню должны поя-

виться на экране. Глобальное выравнивание по левому краю выглядит

ужасно, но центрирование нарушается при выдаче на экран какого-либо

сообщения (например, от cpio). В данном случае сделано выравнивание не

по центру, а по левому краю. Неплохим компромиссом может быть отступ на

три-пять позиций от левого края. Как и в большинстве случаев, когда де-

ло идет об эстетике, вы можете с этим не согласиться.

Вернемся к нашему меню. Для того, чтобы сделать меню на экране и

более эстетичным, и информативным, на экран выводятся дата и время.

(Заметьте, что главное меню очищается каждый раз перед его использова-

нием.) Пример вида экрана приведен ниже.

---------------------------------------

| Среда, май 28 13:18:49

|

| Cpio - Сохранение/восстановление файлов

| ---------------------

| Копирование данных

| Восстановление данных

| Список файлов на носителе

| Полный список файлов на носителе

| <ВК> для выхода

|

| Нажмите b,r,f,l, или <ВК>:


В левом верхнем углу расположен день недели, месяц, день месяца.

Это поля 1, 2 и 3 команды date. В правом верхнем углу расположено теку-

щее время. Это поле 4 команды date. Все эти данные приводятся для того,

чтобы меню на экране смотрелось красиво, было равномерно заполнено и

информативно.

После того, как меню выдано на экран, строка 27 читает команду

пользователя. Заметим, что один из ключей вызывает завершение програм-

мы, если был нажат только возврат каретки. Каким образом мы проверяем

это? Мы заключаем в кавычки входную переменную таким образом, что про-

верка распознает нулевое значение (см. строки 28-30). Если был введен

ноль, мы выходим из текущего цикла while. Тем самым мы попадаем в конец

программы, которая после этого завершает выполнение. Если входное зна-

чение не было равно нулю, мы продолжаем и выполняем в следующей команде

проверку на наличие ошибки.

В строке 32 проводится инициализация переменной ABORT путем

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

скажем, что эта переменная существует, поскольку имеется конфликт между

тем, как выполняется команда break, и структурой данной программы (т.е.

полностью управляемой с помощью меню утилиты).

В строках 34-65 разместился вложенный цикл while, который обраба-

тывает подменю. Причина, по которой мы использовали циклы типа "вечный

while" заключается в том, что они выполняются, пока не получат нужное

входное значение. Как только получены правильные входные данные, мы вы-

ходим из цикла. Это очень простой способ обработки меню.

В строках 36-45 мы снова используем оператор echo для выдачи на

экран полного подменю. Это меню запрашивает имя устройства, которое

используется в командах копирования/восстановления.

Строка 47 читает входные данные от пользователя в переменную

MEDIA. Значение переменной MEDIA затем оценивается в операторе case.

Обратите внимание, что шаблоны сравнения включают символы и в верхнем,

и в нижнем регистре. Это облегчает жизнь пользователя и делает немного

более логичным программирование, уменьшая число проверок на ошибки, ко-

торое мы должны произвести. Также заметьте, что каждый образец заканчи-

вается оператором break. Когда обнаружено допустимое входное значение,

мы желаем продолжать выполнение после конца оператора while, что осу-

ществляется оператором break. Переменная DEV теперь установлена как

маршрут к выбранному устройству.

Ключ "a" в строках 55-60 требует дальнейшей обработки. Пользова-

тель запрашивается об имени устройства, которое он выбрал. Если пользо-

ватель забыл имя или решил не использовать этот ключ, он может ввести

возврат каретки, который распознается как нуль и приводит к выполнению

оператора continue. Это вызывает выполнение следующей итерации текущего

цикла, которая снова выводит подменю. Еще один возврат каретки после

этого может использоваться для выхода из подменю и возврата в главное

меню. В противном случае, если пользователь ввел ненулевое значение,

выполняется оператор break, и цикл меню завершается, имея маршрут, ука-

занный в переменной DEV.

Если пользователь ввел неверное значение, печатается сообщение об

ошибке и подменю выводится снова. Заметьте, что ввод только возврата

каретки в подменю устанавливает переменную ABORT в "on". Почему это

так? Теперь мы подошли к той части, где язык командного процессора неп-

рименим для нашего случая. Сценарий выглядит примерно так. Мы находимся

в подменю. Мы решаем, что не будем здесь производить выбор, поэтому мы

хотим выйти из подменю и вернуться в главное меню (или в предыдущее ме-

ню). Если мы выйдем из цикла while подменю, мы попадем во внешний цикл

while и продолжим обработку запросами о каталоге-источнике и катало-

ге-приемнике.

Если мы попытаемся решить эту проблему путем использования опера-

тора "break 2", мы выйдем из обоих циклов while (попадая в самый низ

программы) и программа завершится, ничего не сделав для нас. Снова не

то, что мы хотим. Что мы действительно хотим, так это выйти из текущего

(внутреннего) цикла и продолжить следующую итерацию во внешнем цикле

для получения главного меню. Нет никакой возможности сказать командному

процессору об этом, поэтому мы создали переменную в качестве флага для

имитации этого действия и назвали ее ABORT. Если мы устанавливаем пере-

менную ABORT в состояние "да", то мы НЕ желаем продолжать работу с ко-

мандой главного меню, а хотим прекратить ее и вернуться в главное меню.

На самом деле это означает продолжить, поэтому в строках 67-69 проверя-

ется именно это. Если флаг ABORT установлен, подменю принудительно за-

вершается и оператор continue заставляет снова печатать главное меню

вместо того, чтобы пытаться выполнить какую-то наполовину определенную

операцию копирования.

В строке 71 мы получаем для проверки команду главного меню и ин-

формацию, необходимую для ее обработки. Четырьмя основными командами

являются копирование, восстановление, выдача списка файлов и выдача

списка файлов с полной информацией. Если введена какая-то другая коман-

да, выдается сообщение об ошибке и главное меню снова выводится на эк-

ран. Единственный способ выхода из главного меню - это нажать возврат

каретки без какого либо-текста перед ним и строка 28 позволит выйти из

цикла.

Команды копирования и восстановления используют относительное име-

нование. Сначала они требуют указать каталог, затем переходят в этот

каталог. Оператор echo и "холостое" чтение переменной CMD просят поль-

зователя вставить дискету (или смонтировать магнитную ленту или еще

что-нибудь) и нажать возврат каретки, когда все готово.

В случае копирования для поиска ВСЕХ файлов, размещенных в дереве

файлов, начиная с текущего каталога, используется команда find. Опера-

тор find выдает отсортированный список файлов, поэтому файлы на носите-

ле с копией отсортированы. Затем отсортированный список файлов переда-

ется по каналу команде cpio с опциями -ocBv. Это означает: "потоковый

вывод, использовать символьные заголовки, блоки размером по 5K, с выда-

чей сообщений". При этом печатаются имена файлов по мере того, как они

копируются на носитель.

В случае операции восстановления используются ключи -icBvdmu. Это

значит "потоковый ввод, использовать символьные заголовки, блоки по 5К,

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

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

дификации, и все файлы безусловно копируются".

Если должен быть выдан только список файлов, то ключами будут или

-icBt для печати таблицы скопированных файлов (это соответствует записи

команды cpio "ls"), или -icBtv для печати таблицы файлов с более под-

робной информацией ("ls -l" в записи для cpio).

В конце выполнения каждой команды главного меню выдается сообщение

hit (Нажмите <ВК>)

Это сделано по той причине, что когда печатается главное меню, оно

очищает экран. Если бы вы хотели получить список файлов, как описано

выше, и не завершить работу, то напечатался бы список, выполнение

достигло бы внешнего оператора "done", внешний цикл снова стартовал бы

и экран очистился бы перед новой выдачей на него главного меню. Уф, на-

конец появился список, даже до того как Эвелин Вуд с высшим образовани-

ем смогла прочитать это! Для того, чтобы задержать очистку экрана, мы

ожидаем нажатие на клавишу. Что бы ни было введено, оно читается в пе-

ременную и снова никогда не используется. Это просто холостая перемен-

ная.


Замечания по операции копирования


Вы можете производить копирование файлов многими путями, но давай-

те рассмотрим некоторые отличия между командами cpio и tar. Первона-

чально командой копирования в UNIX была команда tar. Эта утилита созда-

ния копии на магнитной ленте была предназначена для ведения архивов на

магнитной ленте и выполнения самого копирования. Она работает, но имеет

некоторые особенности. Во-первых, каждый файл, помещаемый на ленту (или

какой-либо носитель, который вы используете), выравнивается на границу

килобайта. Это означает, что если ваш файл состоит из одного байта, ко-

манда tar выделяет минимум 1К вашему файлу, что может привести к значи-

тельной растрате пространства, если у вас много небольших файлов и вы

копируете их на магнитную ленту. Однако команда tar имеет также ряд

неплохих аспектов.

Например, вы можете сказать ей, какой множитель блокировки вы

используете и насколько велик образ копии, так что вы можете разбить

большие копируемые потоки данных на много мелких частей (например k=360

для гибких дисков низкой плотности в системе XENIX). Одним из странных

аспектов команды tar является то, что копия является одним длинным и

непрерывным потоком, а при восстановлении используется уникальный фор-

мат для каждого носителя. Например, вы должны, скажем, скопировать 10M

данных. Вам лучше иметь достаточно отформатированных гибких дисков и

приготовить их до того, как вы начнете копировать командой tar. Когда

дискета заполнится, вы должны прервать выполнение команды и затем снова

продолжить. Пример такой команды мог бы выглядеть так:


cd $HOME

tar cvefbk /dev/fd048ds9 18 360 .


Здесь указано, что требуется скопировать ВСЕ файлы (рекурсивно об-

ходя дерево сверху вниз) из текущего каталога (.) в файл на указанном

устройстве, со множителем блокировки 18 K и размером образа копии 360

Кбайт. Одним из интересных аспектов здесь является то, что когда коман-

да tar рекурсивно проходит вниз по дереву, она получает имена файлов в

порядке расположения описатель файла, что обычно НЕ совпадает с отсор-

тированным порядком. Вы НЕ МОЖЕТЕ получить отсортированный список фай-

лов для копирования командой tar, если только не сделаете еще одну точ-

ную копию всех данных, которые вы хотите скопировать и не разместите

описатель файла в отсортированном порядке. Как это сделать? Вот так:


cd $HOME

find . -print | sort | cpio -pdv /bkpsort


При этом получится новая копия всех ваших данных и имена файлов

разместятся в отсортированном порядке. Если после этого вы перейдете в

каталог /bkpsort и выполните команду tar, файлы будут перенесены на

носитель в отсортированном порядке.

Предположим, что для выполнения копирования требуется 15 дискет.

При восстановлении этого полного набора вы должны вводить приведенную

ниже команду 15 раз, поскольку на каждом из гибких дисков располагается

уникальный образ копии.


tar xvf /dev/fd048ds9


Такие повторные вводы команды раздражают, но они могут облегчить

жизнь, что мы вскоре и увидим.

Команда cpio является следующим поколением команд копирования. Ее

общие функции подобны функциям команды tar, но имеется несколько важных

отличий. Во-первых, вы должны сгенерировать список файлов для cpio, что

означает использование команды find для порождения списка. Поскольку мы

можем конвейером пропустить список, полученный от команды find, через

команду sort, нам нет необходимости делать еще одну копию всех наших

файлов для получения отсортированного списка.

Далее, команда cpio не выполняет выравнивание границу килобайта.

Она пакует все данные непрерывно и имеет магическое число в заголовке

для указания начала каждого нового файла. В команде cpio также нет ука-

зания размера образа на носителе. Как она это узнает? Драйвер уст-

ройства должен определить размер и послать соответствующий сигнал об-

ратно команде cpio, которая после этого приостанавливается и предлагает

вставить следующую дискету. Это все прекрасно до тех пор, пока вы не

попадаете в систему, в которой драйверы ужасны, как в системе XENIX.

Драйверы XENIX не распознают, когда нужно остановиться и продолжают вы-

полнять работу и после того, как достигнут конец гибкого диска. Прог-

рамма cpio должна была бы выполняться одинаково на всех системах, но

она не работает корректно на машинах с системой XENIX.

Одно существенное различие между командами cpio и tar заключается

в получающемся образе копии. Поскольку cpio не различает границ между

различными носителями (дискетами), файлы получаются разорванными между

двумя гибкими дисками. Это значит, что когда вы пытаетесь копировать с

этих 15 дискет, то они являются ОДНИМ непрерывным потоком входных дан-

ных, точно так, как и последовательный поток выходных данных при созда-

нии этой копии. Что произойдет, если дискета номер 2 повредится? ВСЕ

ваши файлы после второй дискеты стали бесполезны. Вы просто потеряли

весь ваш образ копии. Поскольку tar копирует в виде отдельных образов,

когда дискета номер 2 потеряется, вы все равно можете копировать с

дискет 3-15 без проблем.

Еще один прекрасный аспект команды cpio заключается в том, что она

может работать как в формате файловой системы, так и в потоковом форма-

те. Формат файловой системы (опция -p) обращается к блочным уст-

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