экране.
Одним из спорных вопросов является место, где меню должны поя-
виться на экране. Глобальное выравнивание по левому краю выглядит
ужасно, но центрирование нарушается при выдаче на экран какого-либо
сообщения (например, от 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 заставляет снова печатать главное меню
вместо того, чтобы пытаться выполнить какую-то наполовину определенную
операцию копирования.
18 fi
формацию, необходимую для ее обработки. Четырьмя основными командами
являются копирование, восстановление, выдача списка файлов и выдача
списка файлов с полной информацией. Если введена какая-то другая коман-
да, выдается сообщение об ошибке и главное меню снова выводится на эк-
ран. Единственный способ выхода из главного меню - это нажать возврат
каретки без какого либо-текста перед ним и строка 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 рекурсивно проходит вниз по дереву, она получает имена файлов в