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

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

Содержание


Формат вызова
Возможные модификации командного файла
Формат вызова
Подобный материал:
1   ...   13   14   15   16   17   18   19   20   ...   45

руктурированным устройствам (опции -i и -o), таким как магнитная лента

или гибкий диск с форматом низкого уровня. Cpio - это прекрасная утили-

та для использования ее при копировании файловых деревьев системы на

жестком диске.

Как же управляется с этим система 4.2 BSD? В течение многих лет

применялась команда tar для пересылки туда и обратно, как описано на

страницах руководства по tar(1). Не самый элегантный подход, но рабо-

тоспособный. Сейчас они имеют ключ -r (для рекурсивного обхода дерева

сверху вниз) для обычной команды cp. Я же по-прежнему считаю, что ко-

манда cpio лучше.


3.4. Средства проверки операций копирования

3.4.1. dsum - контрольные суммы двух катологов


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


Имя: dsum

_____________________________________________________________

dsum Контрольная сумма двух каталогов


НАЗНАЧЕНИЕ


Выдает на экран выходные данные команды sum системы UNIX для двух

копий файлов из двух разных каталогов в одной строке. Это позволяет

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

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


ФОРМАТ ВЫЗОВА


dsum [-c|-o] control_dir backup_dir


Пример вызова

dsum $HOME/bin /mnt

Просматривает, были ли какие-либо файлы изменены при копировании

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

талоге /mnt.


Командный файл dsum


1 :

2 # @(#) dsum v1.0 Dual directory sum Author: Russ Sage


4 if [ $# -lt 2 -o $# -gt 3 ]

5 then echo "dsum: invalid argument count" >&2

6 echo "usage: dsum [-c|-o] control_dir backup_dir" >&2

7 echo " -c = C source files, -o = object files" >&2

8 exit 1

9 fi


11 case $# in

12 2) FLIST=*;;

13 3) case $1 in

14 -c) FLIST=*.c;;

15 -o) FLIST=*.o;;

16 *) echo "dsum: invalid argument $1" >&2

17 echo "usage: dsum [-c|-o] control_dir

bacup_dir" >&2

18 exit 1;;

19 esac

20 shift;;

21 esac


23 for FILE in $1/$FLIST

24 do

25 BASEF=`basename $FILE`

26 if [ `expr $BASEF : '.*'` -lt 7 ]

27 then echo "`$BASEF: \t'`sum $FILE | cut -d' '

-f1`\t\c"

28 else echo "$BASEF:\t`sum $FILE | cut -d' '

-f1`\t\c"

29 fi

30 sum $2/$BASEF | cut -d' ' -f1

31 done


Переменные среды выполнения


BASEF Содержит базовое имя файла из полного маршрутного

имени

FILE Содержит имя каждого проверяемого файла

FLIST Содержит указание на тип проверяемых файлов


Описание

Зачем нам нужен dsum?


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

содержат все: исходный код, перемещаемые модули, объектный код, данные,

тексты. Другим аспектом среды разработки программ является то, что эти

файлы обычно рассыпаны по многим различным машинам (или группам машин,

может быть и такой случай). В этом случае всегда кажется, что имеется

очень много перемещений файлов: эти файлы передаются из одной системы

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

Похоже на то, как в армии роют ямы: вы делаете это, потому что вам при-

казано.

Когда вы перемещаете много файлов, то какой путь является лучшим

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

вами копия является ТОЧНО такой, как и оригинал? Если вы внесли ошибку

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

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

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

Одним из способов слежения за копиями является использование ко-

манды sum. Эта команда читает данные и выводит число, являющееся разно-

видностью контрольной суммы. Другими утилитами UNIX, которые делают

что-то подобное, являются cmp для сравнения объектных файлов и diff для

обнаружения различий в текстовых файлах.

Автор привык думать, что sum будет сообщать об отличии даже в од-

ном бите (своего рода циклическая избыточная проверка), но это оказа-

лось совсем не так. Недавно имелся 35 Кбайтный файл, содержащий в виде

длинного формата список файлов, которые должны были быть скопированы. В

действительности, там были два файла, один из которых был отсортирован,

а другой нет. Они были одного размера, и sum выдала одно и то же число

для обоих файлов. Когда же cmp сравнила эти два файла, оказалось, что

39-е байты отличаются. Как мы можем объяснить тот факт, что sum

рассматривала эти два файла как совершенно одинаковые? Возможно, sum

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

одинакова, даже хотя один из файлов был отсортирован, а другой нет.

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

ку каждого бита. Только проверка алгоритма работы программы в исходном

модуле позволит убедиться в этом. Конечно, в большинстве случаев, если

файл отличается от оригинала, то это не является простой перестановкой

данных, так что sum все-таки полезна.


Что делает dsum?


Dsum - это утилита, которая выполняет проверку после копирования.

Она предполагает, что файлы скопированы из каталога-источника в ката-

лог-приемник. Каталог-источник назван управляющим каталогом, поскольку

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

ляющем каталоге печатается его имя вместе со значением его контрольной

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

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

Польза от получения всей информации от dsum в одной строке заклю-

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

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

информации.

Альтернативой для dsum может быть выполнение какого-либо сценария,

подобного приводимому ниже.

1. Скопируйте ваши файлы в другой каталог.

2. Подсчитайте контрольную сумму всех файлов из управляющего

каталога и выведите результат в какой-либо файл.

3. Подсчитайте контрольную сумму всех файлов в каталоге,

содержащем копию, и выведите результат в какой-либо файл.

4. Сравните эти два файла командой diff для того, чтобы

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

Это не дает вам даже хорошего вывода на экран о том, что происхо-

дитгиЭто не дает вам даже хорошего вывода на экран о том, что происхо-

Dsum не проходит вниз по дереву файлов, потому что большинство ко-

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

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

программы существенно понижается.

По умолчанию сравниваются ВСЕ файлы. Это предполагает, что вы ско-

пировали все файлы в каталог копирования. В некоторых случаях вы можете

захотеть копировать только выбранные файлы, такие как *.c (все ваши

исходные файлы). В этом случае управляющий каталог содержит множество

файлов, а каталог с копиями содержит только файлы с расширением .c.

Для поддержки таких случаев в программу включены ключи -c и -o.

Ключ -c указывает только файлы типа *.c из управляющего каталога. В ре-

зультате производится проверка только файлов *.c в каталоге с копией.

Ключ -o выполняет то же самое для файлов, соответствующих *.o.

Примеры

1. $ mount /dev/fd0 /mnt

$ cp /usr/include/* /mnt

$ dsum /usr/include /mnt

Монтирует гибкий диск в каталог /mnt. Копирует все файлы заголов-

ков в каталоге /usr/include на гибкий диск. Проверяет копии, используя

dsum для исходного каталога и для каталога с копией.


Примечание: Указывая копировать *, мы вообще не попадем

в каталог /usr/include/sys.


2. $ dsum . ..


Используя в качестве управляющих файлов файлы в текущем каталоге,

сверить каждый файл с одноименным файлом в родительском каталоге.


Пояснения


В строках 4-9 производится проверка на наличие ошибок. Если указа-

но менее двух аргументов, значит управляющий каталог и/или каталог ко-

пии не указан и в результате обнаруживается ошибка. Если количество ар-

гументов превышает три, значит, указано еще что-то кроме ключа -c и

двух каталогов, что также является ошибкой. Все остальное (два или три

аргумента) рассматривается как допустимое значение.

В строках 11-21 производится инициализация переменной FLIST. FLIST

- это управляющая переменная, которая определяет имена файлов, на кото-

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

на каталогов ($# = 2), FLIST присваивается значение по умолчанию * (все

файлы) в строке 12. Значение * присваивается переменой FLIST и не трак-

туется в это время как метасимвол (это особенность командного процессо-

ра). Если в командной строке указан ключ ($# = 3), производится провер-

ка первой переменной и FLIST получает соответствующее значение, *.c или

*.o. Если указана не такая опция, выводится сообщение об ошибке и прог-

рамма завершается.

В строках 23-31 выполняется сама работа. Здесь выполняется цикл

for, который проходит по списку слов, созданному управляющим каталогом

в соответствии со значением переменной FLIST. В строке 23 переменная

FLIST расширяется фактически с символа * в имя каждого файла. Тем самым

цикл for получает данные для использования. Следовательно, переменная

FLIST является полным маршрутным именем каждого файла в управляющем ка-

талоге.

Строка 25 разбирает расширение, сделанное в строке 19. Переменная

BASEF получает базовое имя полного маршрута из переменной FILE. Причи-

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

на каталог копии нам необходимо только имя файла. (В системе UNIX ко-

манда basename возвращает последний элемент в указанном маршруте, т.е.

само имя файла, если маршрут содержит промежуточные каталоги.)

Строки 26-29 выводят первую часть выходного сообщения. Оператор

if-then использован потому, что нам нужно менять выходное сообщение в

зависимости от того, сколько символов содержит имя файла. Строка 26 оп-

ределяет длину имени файла, используя команду expr. Команда expr может

быть использована для сравнения двух строк и получает количество сов-

павших символов. Сравнение имени файла со "всеми символами" (*), таким

образом возвращает длину строки. (У вас может возникнуть желание обра-

титься к expr(1), чтобы получить информацию о других хитростях этой

многоцелевой команды.)

Это возвращаемое значение используется в операторе test для опре-

деления, содержит ли имя файла менее семи символов: возможно всего один

или два символа. В последнем случае, если мы делаем табуляцию, мы полу-

чим только первую позицию табуляции. Для получения последующих табуля-

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

ющего поля табуляции. (Если было 3-6 символов, мы все равно остановимся

на поле второй табуляции, т.е. это место работает верно.) Затем отобра-

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

буляции, что нам и требовалось.

Если имя файла содержит более семи символов, мы уже находимся в

первой позиции табуляции или за ней. Таким образом, следующий символ

табуляции передвинет нас во вторую позицию табуляции. Эффект заключа-

ется в том, что для размещения колонок не имеет значения размер имени

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

ляет избавиться от "блюза ползущих колонок", когда колонки сдвигаются в

зависимости от размера отображаемой информации. В качестве примера та-

кого эффекта может служить стандартная команда sum. Ее выход выглядит

так:

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

| 4243 3 autobkp

| 247 1 can

| 25167 6 cpiobr

| 186 3 dosflp

| 56864 2 dsum

| 2782 1 log

|


С другой стороны, выход dsum очень ясный и четкий, не сдвигается

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

просмотр информации.

Чудо вывода в одну строку совершается в строке 27 (для файлов с

именами менее 7 символов) или в строке 28 (для файлов с более длинными

именами). Внутри команды echo в каждом случае мы прячем другие команды,

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

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

полного маршрутного имени. Обратите внимание, что имена файлов не со-

держат информацию о том, из какого они каталога. Затем мы несколько

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

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

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

лога. Команда sum выводит три значения (контрольная сумма, число бло-

ков, занятых файлом, и само имя файла). Нам нужно получить только пер-

вое значение, которое извлекается путем выполнения команды sum и пере-

дачи ее выхода по каналу команде cut, которая и возвращает первое поле.

После того, как значение контрольной суммы напечатано, мы отображаем \c

для запрещения перехода на новую строку. Это сохраняет курсор в той же

строке.

Здесь начинает работать строка 30. Она генерирует контрольную сум-

му того же файла в каталоге копии ($2 в командной строке) и текущее имя

файла, вырезая только число, и печатает его правее курсора в той же

строке.

Цикл завершается, когда все файлы из управляющего каталога будут

проверены командой sum.


ВОЗМОЖНЫЕ МОДИФИКАЦИИ КОМАНДНОГО ФАЙЛА


Неплохой модификацией может быть вариант, чтобы dsum печатала не

только значения, как это сделано, но и флаг в конце строки в случае,

когда два файла отличаются. Тогда у нас не было бы необходимости

просматривать непосредственно числа. Мы ищем флаг и сразу видим, когда

что-то не так.

Ниже приводится решение проблемы вывода флага для того, чтобы об-

легчить вам работу. Оно не включено в представленную выше утилиту по

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

просто. Вы можете сами сделать эту модификацию в качестве упражнения.

Текст программы, выполняющей эту работу, выглядит так:


for FILE in $1/$FLIST

do

BASEF=`basename $FILE`

S1=`sum $FILE 2>&1 | cut -d' ' -f1`

S2=`sum $2/$BASEF 2>&1 | cut -d' ' -f1`

if [ "$S1" = "$S2" ]

then M=""

else M="<---"

fi

if [ ` expr $BASEF : '.*'` -lt 7 ]

then echo "$BASEF: \t$S1\t$S2 $M"

else echo "$BASEF:\t$S1\t$S2 $M"

fi

done


Подход к решению немного отличается от решения, принятого при на-

писании dsum, поскольку вы не можете генерировать контрольную сумму на

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

То, что мы ищем, появляется в шестой строке. Если две контрольные суммы

различны, переменная M устанавливается соответствующим образом. Если

файлы различаются, переменная M получает стрелку, указывающую на то,

что копия плохая.


3.4.2. log - меню доступа к файлам протокола копирования


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


Имя : log

_________________________________________________________________________

log Меню доступа к файлам протокола копирования


НАЗНАЧЕНИЕ


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

от утилиты autobkp.


ФОРМАТ ВЫЗОВА


log


Пример вызова

log


Командный файл log


1 :

2 # @(#) log v1.0 Menu access to backup logfiles Author: Russ Sage


4 c

5 set `date`

6 echo "


8 $1, $2 $3 $4


10 Logfile Menu

11 ----------------

12 1 - list all log file names

13 2 - display log of home backup

14 3 - display log of product backup

15 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 обра-

щаться самой к себе позволяет вам добавлять неограниченное число файлов

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