ПРИЕМЫ ПРОФЕССИОНАЛЬНОЙ РАБОТЫ В UNIX ГЛАВА 3. ПОДДЕРЖКА ФАЙЛОВОЙ СИСТЕМЫ СОДЕРЖАНИЕ ВВЕДЕНИЕ 3.1. СОПРОВОЖДЕНИЕ ФАЙЛОВ 3.1.1. Операции сопровождения 3.1.2. Средства пересылки файлов 3.1.3. Средства копирования 3.1.4. Средства проверки операции копирования 3.2. ПЕРЕСЫЛКА ФАЙЛОВ 3.2.1. cptdir - копирование дерева каталога 3.2.2. can - удаление файлов в "мусорную корзину" 3.2.3. dosflp - копирование файлов с гибкого диска формата MS-DOS с использованием символов шаблона в именах файлов 3.3. СРЕДСТВА ПОЛУЧЕНИЯ РЕЗЕРВНЫХ КОПИЙ 3.3.1. autobkp - автоматически наращивамый файл резервной копии 3.3.2. cpiobr - копирование и восстановление файлов в виде потока данных 3.4. СРЕДСТВА ПРОВЕРКИ ОПЕРАЦИЙ КОПИРОВАНИЯ 3.4.1. dsum - контрольные суммы двух катологов 3.4.2. log - меню доступа к файлам протокола копирования ВВЕДЕНИЕ Даже "небольшая" система UNIX с малым числом пользователей порож- дает сотни файлов в ходе обычной работы. В процессе программирования вы можете создавать множество файлов для различных версий ваших программ. Ведение почты и запись текста при помощи редактора vi способствует то- му, что накапливается еще больше файлов. Такие утилиты, как uucp, lp и другие добавляют еще больше файлов. Если у вас система UNIX установлена на микро-ЭВМ, то ваш жесткий диск начинает переполняться. В больших многопользовательских системах дисковая память редко считается пробле- мой, но в действительности всегда кажется, будто файлы стремятся расши- риться до заполнения всей доступной дисковой памяти. Поэтому каждый пользователь должен нести ответственность за расход дискового прост- ранства. (Если вы платите за дисковую память, то у вас также могут быть финансовые стимулы.) Однако, то, что вы хотите сохранить, вы хотите СОХРАНИТЬ. Именно здесь начинается работа по созданию резервных копий. 3.1. СОПРОВОЖДЕНИЕ ФАЙЛОВ В предыдущей главе мы разработали некоторые средства поиска и отображения информации, помогающие нам поддерживать жизненный путь всех наших файлов. Теперь мы собираемся обратиться к важнейшим рутинным ра- ботам, которые позволят избежать хаоса и катастрофы. Сопровождение файлов означает избавление от файлов, которые нам больше не нужны и в то же время систематическое копирование тех файлов, которые мы хотим сохранить. Для этого требуется возможность использова- ния разнородных доступных носителей данных. Сопровождение файлов подра- зумевает также ряд систематических, повторяющихся задач, а это означа- ет, что мы можем создать средства системы UNIX для автоматизации этого процесса. 3.1.1. ОПЕРАЦИИ СОПРОВОЖДЕНИЯ Сопровождение файлов включает два вида операций: создание резерв- ных копий (копирование) и удаление "мусора". Копирование - это дань уважения, которую мы платим за хрупкость физических данных в руки Мерфи и других богов энтропии. Хорошее средство копирования является быстрым, гибким, простым в использовании и стимулирует пользователей часто копировать самые важные файлы. В последующем тексте будут представлены различные методы копирования, пригодные для разных конфигураций системы и типов носителей. Имеется два вида резервных копий: "мягкие" и "твердые". "Мягкие" резервные копии - это копии в другом файле или каталоге в той же или в другой файловой системе (т.е. разделе) на том же или другом жестком диске. Такого рода копирование сделать легко и оно предохраняет от на- носимого самому себе ущерба, такого как удаление файла по невниматель- ности. Чаще всего для такого типа копирования используется наше средство cptdir. Основной недостаток мягкого копирования заключается в том, что вы по-прежнему уязвимы для таких воздействий, которые влияют на ваш физический носитель (обычно жесткий диск) так, что и оригинал и копия оказываются разрушенными. "Твердая" копия - это копия на другом устройстве или даже в другой системе UNIX. Средства, представленные ниже в данной главе, управляют такого рода копированием и дают вам возможность выполнять копирование такого типа и с такой периодичностью, которые соответствуют объему ва- шей вычислительной системы, уровню ее активности и важности хранимых данных. Твердое копирование всегда несколько утомительно, потому что диски или ленты должны быть смонтированы (или должна быть установлена связь с другой системой), а эта операция требует много времени. Преимущество, естественно, заключается в том, что вы больше не зависите от целост- ности какого-либо одного устройства. Автоматизируя нашу процедуру копирования, мы стараемся сделать его как можно менее болезненным. Делая наши средства копирования в какой-то степени разумными, мы можем выбрать только файлы, которые нуждаются в копировании, и тем самым сохранить время и память. Наилучший способ обеспечить, чтобы копирование выполнялось регулярно - минимизировать время и требуемые для этого усилия. Наконец, создание процедур для про- верки правильности копий даст вам спокойствие духа. "Удаление мусора" можно автоматизировать путем указания и подго- товки к удалению файлов, которые, вероятно, будут временными, либо ка- ких-то других файлов, которые созданы (но не обязательно разрушены) при компиляции, выполнении конвейеров или другими операциями. Вы также мо- жете указывать файлы, специфичные для ваших работ как не подлежащие удалению. 3.1.2. СРЕДСТВА ПЕРЕСЫЛКИ ФАЙЛОВ Первая группа средств - это простые универсальные переносчики фай- лов. Программа cptdir может копировать каталог (и любые подчиненные ка- талоги, лежащие ниже в дереве) в каталог-приемник. Каталог-приемник - это обычно каталог, назначенный в качестве резервной копии для некото- рого проекта. Программа can берет на себя необходимую рутинную работу - убирает "мусор". Эта программа позволяет вам выбрать типы временных файлов, ко- торые должны периодически удаляться. Направляя их в "мусорный" каталог, can предоставляет вам возможность просмотреть все, что было удалено, и восстановить то, что вы на самом деле хотите сохранить. Программа dosflp допускает применение символов-шаблонов в именах файлов, используемых при копировании отобранных файлов с дискет формата MS-DOS в XENIX. Это упрощает операцию копирования и уменьшает число на- жатий на клавиши. 3.1.3. СРЕДСТВА КОПИРОВАНИЯ Далее представляется "рабочая лошадка" - средства копирования. Autobkp использует список маршрутных имен, чтобы определить, какие части файловой системы должны быть проверены. Затем эта программа копи- рует из выбранных областей те файлы, которые были добавлены или измене- ны в последние 24 часа. Cpiobr предоставляет интерактивное дополнение к команде cpio системы UNIX. Она позволяет вам скопировать файлы с жесткого диска на гибкий и, если необходимо, восстановить их с гибкого диска на жесткий. 3.1.4. СРЕДСТВА ПРОВЕРКИ ОПЕРАЦИЙ КОПИРОВАНИЯ Выполнение копирования не избавит вас от волнений, пока вы не бу- дете знать, что вы скопировали все, что хотели, и что копирование прош- ло корректно. Программа dsum использует контрольную сумму для проверки того, что исходный каталог и каталог-копия содержат одни и те же файлы. Программа log отображает регистрационный файл, чтобы показать, какое автоматическое копирование выполнялось в четыре часа утра, когда вы (надеемся) спали. При создании этих средств мы просмотрим некоторые важные команды системы UNIX и обнаружим новые способы их использования. Когда вы про- работаете всю данную главу, вы будете знать, как работать "с мельчайши- ми частицами" при использовании файловой системы UNIX. Вы сможете авто- матизировать иную большую область ваших компьютерных будней. Вы должны суметь создать пользовательские утилиты копирования и верификации, удовлетворяющие вашим нуждам. Вы сможете перевести вашу систему в режим работы, обеспечивающий ей самостоятельное выживание. (Мы оставляем фи- лософам определять, даст ли это вашему компьютеру примитивную форму жизни!) Между прочим, многие средства в данной главе пользуются преиму- ществами рекурсивных методов обхода дерева, которые мы разработали в предыдущей главе. Вы можете просмотреть тот материал, если у вас име- ются затруднения в понимании того, что представлено здесь. 3.2. ПЕРЕСЫЛКА ФАЙЛОВ 3.2.1. cptdir - копирование дерева каталога ИМЯ: cptdir cptdir Копирует дерево каталога в другое место ФУНКЦИЯ Копирует дерево файловой системы, корень которого расположен в ка- талоге, в другой каталог системы. Нет ограничений на какой-либо специ- фический каталог или жесткий диск. ФОРМАТ cptdir [-s] каталог-источник каталог-приемник ПРИМЕР ВЫЗОВА cptdir $HOME /bkp Копирует каждый файл из $HOME в каталог /bkp. КОМАНДНЫЙ ФАЙЛ cptdir 1 : 2 # &(#) cptdir v.1.0 Copy a directory tree Autor: Russ Sage 3 4 if [ $# -lt 2 -o $# -gt 3 ] 5 then echo "cptdir: argument error" >&2 6 echo "usage: cptdir [-s] srcdir desdir" >&2 7 echo " -s silent mode" >&2 8 exit 1 9 fi 10 11 if [ "$1" ="-s" ] 12 then OPT="-pd" 13 shift 14 else OPT="-pdv" 15 fi 16 17 SRC=$1 18 DEST=$2 19 umask 0 20 21 if [ -d $DEST ] 22 then echo "\"$DEST\" already exist. Remove it? (y/n): \c" 23 read CMD 24 if [ "$CMD" = "y" ] 25 then rm -rf $DEST 26 mkdir $DEST 27 fi 28 else mkdir $DEST 29 fi 30 31 if [ "`echo $DEST|cut -c1`" = "/" ] 32 then cd $SRC 33 find . -print | sort | cpio $OPT $DEST 34 else PWD=`pwd` 35 cd $SRC 36 find . -print | sort | cpio $OPT $PWD/$DEST 37 fi ПЕРЕМЕННЫЕ СРЕДЫ CMD Команда, полученная от пользователя DEST Каталог-приемник, в который нужно копировать OPT Опции, которые передаются утилите cpio PWD Текущий рабочий каталог SRC Каталог-источник, из которого нужно копировать Описание Зачем нам нужен cptdir? Мы уже отмечали необходимость в дополнительных командах, которые рекурсивно обходят древовидную структуру файловой системы UNIX. В ран- них версиях UNIX единственная команда tar могла управлять движением по дереву. В более новых версиях системы имеется опция -r в команде cp, которая делает cp рекурсивной (эта возможность реализована только в последней версии System V) и команда cpio. Последняя является многоце- левой командой копирования, которая может иметь дело как с потоковым форматом, так и с форматом файловой системы. Проблема при использовании даже таких улучшенных стандартных ко- манд системы UNIX состоит в том, что вам необходимо указать множество деталей и убедиться в том, что вы правильно используете синтаксис. Ошибки могут привести к потере времени и даже хуже того, к неожиданным побочным эффектам. С некоторыми из этих эффектов связаны изменения прав доступа и владельца, порядок распределения индексных дескрипторов фай- лов (inode), размещения файлов-приемников и результирующие полные име- на. Очень много необходимо запомнить и заново вызывать каждый раз при копировании. Поскольку такое копирование делается не часто, тяжело за- помнить все эти детали. Мы разрешаем эту проблему, автоматизируя детали процесса и в то же время предоставляя пользователю гибкость и управле- ние результатами. Мы создаем инструменты для управления файлами, кото- рые являются хорошими дополнительными средствами к основным командам системы UNIX. Что делает cptdir? Процедура cptdir копирует каталог (и все дерево под ним, если оно существует) в другой каталог системы. Поскольку каталоги предусматрива- ют логический доступ и не являются аппаратно-зависимыми (в отличие от имен устройств), то вы можете легко копировать файлы в другое место на том же диске или копировать их на другой диск полностью без специально- го синтаксиса или опций. Вы можете указать, хотите ли вы, чтобы на экран выводились имена копируемых файлов. Если вы не хотите этого, используйте опцию -s ("silent" - молчаливый). По умолчанию используется режим "verbose" (многословный), который отображает имена по мере копирования файлов. Заметьте, что это копирование, а не перемещение файлов. Недостаток копирования в отличие от перемещения заключается в том, что если прием- ником является каталог на том же диске, то вам требуется дополнительное место на диске для размещения второго образа. Вам также необходимо иметь достаточно описателей файлов (inodes) для сохранения всех файлов. В противном случае вы можете лишиться шанса сбросить в "мусорную корзи- ну" ваши рабочие файлы. В командной строке допустимо указание каталога-источника и имя ка- талога-приемника. Единственный ключ, допустимый в командной строке - это "-s". Любой другой ключ приводит к завершению команды, не вызывая никаких разрушений. Вы, конечно, можете добавить программный код с целью проверки опции и выдачи сообщения о допустимых ключах, если ука- зано нечто отличное от -s. Если вы делаете еще какую-либо проверку на наличие ошибок сверх того, что требуется для предотвращения разрушения данных или системы, то это дело личного вкуса. Минимизация проверок на наличие ошибок дает более компактные и быстрые сценарии, подходящие для опытных пользователей. Если указанный каталог-приемник не существует, то он создается. Если каталог-приемник уже существует, выдается сообщение об этом и вам задается вопрос о том, хотите ли вы очистить его. Если вы ответите "yes", каталог уничтожается и создается снова пустым. Если вы ответите "no", каталог остается таким, какой есть и копируемые файлы просто до- бавляются к уже существующим в наличии. При этом может возникнуть неко- торая путаница, особенно если некоторые файлы с такими именами уже су- ществуют в каталоге-приемнике. В большинстве случаев, однако, у пользо- вателей не появляется желания добавлять свою копию в существующий ката- лог. Тем не менее каталог-приемник должен быть создан, поскольку необ- ходимо его наличие, чтобы команда cpio работала правильно. Если же его нет, cpio не выполнится и выдаст сообщение об ошибке. Процедура cptdir начинает копирование путем прохождения по катало- гу-источнику и формирования списка файлов, находящихся в нем, рекурсив- но обходя дерево сверху вниз. В результате может получиться, что скопи- руется больше, чем вы планировали, поэтому вам необходимо знать размер файловой структуры, которую вы хотите скопировать. Затем файлы копиру- ются в каталог-приемник. Исходные файлы никак не модифицируются и не изменяются (за исключением того, что дата последнего доступа может быть модифицирована). Когда идет копирование, на экран выдается сообщение от cpio, кото- рое показывает полный маршрут к файлам-приемникам. Этот маршрут должен соответствовать маршруту, указанному в командной строке, в противном случае что-то не так. Примеры 1. $ cd /mnt $ cptdir /bin . Перейти на другой диск (обычно смонтированный в каталоге /mnt) и копировать все файлы из каталога /bin в текущий каталог. Обратите вни- мание, что результирующими файлами будут /mnt/*, что может не совпадать с вашим желанием. 2. $ cd /bin $ cptdir . /mnt/bin То же, что и в предыдущей команде, но обратите внимание, что точка изменила свою позицию. Команда указывает копирование всех файлов теку- щего каталога в каталог /mnt/bin. Получаются файлы /mnt/bin/*, что выг- лядит более резонным. 3. $ cptdir /bin /mnt То же, что и в примере 1. 4. $ cptdir /bin /mnt/bin То же, что и в примере 2. Пояснения В строках 4-9 производится проверка аргументов командной строки. Если указано меньше двух аргументов, этого недостаточно. Как минимум должны быть указаны имена каталога-источника и каталога-приемника. Бо- лее трех аргументов слишком много. Самое большее, там должны быть опция -s, каталог-источник и каталог-приемник. В строках 11-15 устанавливаются ключи команды cpio. По умолчанию это pdv, что означает "pass" (передача) для копирования в формате фай- ловой системы (в отличие от необработанного потока данных), "directory" (каталог) для создания каталога при необходимости и "verbose" (мно- гословный) для выдачи имен файлов по мере их копирования. Если первым позиционным параметром является ключ -s, который указывает запуск cptdir в молчаливом режиме, ключи команды cpio не содержат ключа выдачи сообщений и, таким образом имена файлов не выдаются на экран. Строки 17,18 и 19 устанавливают каталоги "откуда" и "куда" и уста- навливают переменную umask в 0. Переменная umask определяет подразуме- ваемые права доступа для всех файлов, созданных нашим командным про- цессором. Мы изменяем umask для гарантии того, что все файлы копируются в дерево-приемник и ни один из них не будет заблокирован из-за отсутствия прав чтения или записи. Побочным эффектом является то, что все каталоги имеют права доступа вида rwxrwxrwx, а все файлы - вида rw-rw-rw-, что может потребовать изменений для обеспечения вашей безо- пасности. Изменение umask имеет действие только на время работы проце- дуры. Когда cptdir завершается, umask вашего вызывающего командного процессора остается неизменным. Строки 21-29 выполняют проверку каталога-приемника. Если он уже существует, вас запрашивают, нужно ли его удалить и заново создать. Если он не существует, он создается для работы cpio. Строки 31-36 выполняют непосредственно копирование. Прежде чем объяснить, что здесь делается, давайте сперва посмотрим, как работает cpio. Поскольку оператор find генерирует список файлов, нам необходимо представлять, как его выход может влиять на выполнение cpio. Если мы указали "find . -print", то полные имена файлов будут иметь точку впереди, например: ./dir ./dir/file1 ./dir/file2 Это относительная нотация, которая очень полезна, когда вы не хо- тите, чтобы ваши файлы передавались согласно абсолютным маршрутным име- нам, но хотим сохранить их взаимосвязь друг с другом. Если на них ссы- латься относительно точки, то место, куда они будут помещены, может быть, где угодно. Однако, если мы скажем "find /dir -print", список бу- дет выглядеть так: /dir /dir/file1 /dir/file2 В обоих случаях мы ссылаемся на наш текущий каталог, но применение записи вида /dir заставляет полное имя начинаться с "/" и не допускает использование относительной нотации. Передача такой же информации ко- манде cpio может радикально изменить место размещения ваших файлов. Например, если я сказал "cd /src; find . -print | cpio -pdv /dest", ре- зультирующий список будет таким: /dest/./dir /dest/./dir/file1 /dest/./dir/file2 где на первом месте стоит, вероятно, то, что вы хотели. Однако, если я сказал "find /src -print | cpio -pdv /dest", результирующие маршрутные имена будут такими: /dest/src/dir /dest/src/dir/file1 /dest/src/dir/file2 что не очень хорошо, поскольку это создает уровень каталога, в ко- тором нет необходимости. Заметьте, что имя каталога "src" было перехва- чено при распечатке. Это произошло потому, что его выдал find, а cpio считает, что src было частью имени каталога-приемника. Повсеместное использование относительной нотации может привести нас к потере уже имеющейся информации. Например, если бы я сказал "cd /nowhere; find /src ....", каталог-приемник получил бы неверное имя. Мы должны уметь использовать этот тип нотации и не попадать в ловушки син- таксиса. Это и есть то, что делает cptdir. В строке 31 производится проверка на то, является ли первый символ в маршрутном имени целевого каталога символом "косая черта" ("/"). Если да, то мы точно знаем, что имя каталога-приемника выражено в виде абсо- лютного маршрутного имени, поэтому мы можем сменить каталоги без потери информации о нашем текущем каталоге. В строках 32-33 мы переходим в ка- талог-источник и копируем файлы. Но если первый символ каталога-приемника НЕ является наклонной чертой, используемая нотация является относительной. Это значит, что если мы сменим каталог, мы потеряем информацию о том, где мы находи- лись, когда был запущен командный файл. Чтобы избежать этого, мы полу- чаем в строке 34 полное имя текущего каталога путем перехвата вывода команды pwd и присвоения этого значения переменной таким образом, что позже мы сможем ее восстановить. Затем мы переходим в каталог-источник и копируем файлы, используя префикс абсолютного маршрутного имени от команды pwd и относительный суффикс того места, где мы находимся. Причиной того, что мы так поступаем, является использование от- носительной (точечной) нотации в операторе find. Как можно было видеть в предыдущем описании, отказ от использования точечной нотации может привести к путанице в маршрутных именах каталога-приемника. Для того чтобы всегда использовать точку в операторе find, нам необходимо убе- диться, куда мы собираемся пересылать файлы. Еще раз напомним, что ко- манда cd действует только для данного командного процессора "низкого" уровня, поэтому она не влияет на тот командный процессор, который за- пустил командный файл. Вообще, командный файл должен оставить пользова- телей в тех же условиях, в которых они находились перед его запуском, за исключением выполнения необходимых работ, при которых не произво- дится смена текущего каталога. Когда cptdir завершается, управление возвращается вызывающему ко- мандному процессору, который по-прежнему ведет свой собственный текущий каталог. Напомним, что всегда, когда вы переходите на более низкий уро- вень командного процессора, экспортируемые переменные передаются вниз, но НИЧЕГО не передается наверх. ВОЗМОЖНЫЕ МОДИФИКАЦИИ КОМАНДНОГО ФАЙЛА В нынешней реализации никакие дополнительные ключи не допускается передача никаких дополнительных ключей команде cpio. Что случится, если вы захотели заменить копирование файлов, где это возможно, созданием ссылок (ключ -l) или не менять время последнего доступа к исходному файлу при его копировании (опция -a)? Такие возможности были бы недо- пустимы. Можно легко добавить возможность передачи дополнительных аргумен- тов. Они должны быть опознаны как аргументы, сохранены и затем выбраны из командной строки. Для этого потребуется такой цикл: for ARG in $* do if [ "`echo $ARG|cut -c1`" = "-" ] then CPIOARG="CPIOARG $ARG" shift fi done Затем переменная CPIOARG может быть передана команде cpio. Еще одна область, где могут быть произведены изменения - это уп- равление правами доступа к файлам. Как объяснялось ранее, значение 0 для umask делает все права такими, что они разрешают запись. Если это вам не подходит, оператор find может быть изменен так, что будет произ- водиться выборочное копирование (и изменение прав доступа). Предположим, например, вы имеете каталог с двумя файлами. Если вы- полнился оператор "find /dir -print", список файлов будет таким: /dir /dir/file1 /dir/file2 Обратите внимание, что имя каталога появляется первым. Проблема возникает, если имя каталога не принадлежит вам или вы не имеете права записи. Происходит следующее: имя каталога копируется первым, устанав- ливаются права доступа (блокируя вас) и после этого file1 и file2 не могут быть скопированы в каталог dir. В cptdir мы применяем решение из- менить umask так, чтобы вы всегда имели права записи. Это своего рода клудж, но он работает. Другой путь - это изменить оператор find. Выполнение оператора "find /dir -depth -print" сгенерирует такой список файлов: /dir/file1 /dir/file2 /dir Обратите внимание, что имя каталога стоит ПОСЛЕДНИМ! Это правиль- но. Ключ -depth переворачивает список файлов так, что имя каталога пе- чатается последним. Что это дает? Фокус в том, что сначала копируются file1 и file2, а затем устанавливаются права доступа данного каталога. Вы можете за- писать файлы в каталог, для которого вы не имеете права записи. Благо- даря тому, что файлы копируются первыми, вы можете не беспокоиться о том, какого рода права доступа имеет этот каталог. К сожалению, ключ -depth команды find поддерживается не всеми версиями системы UNIX. 3.2.2. can - удаление файлов в "мусорную корзину" ---------------------------------------------------------------------- Имя: can ______________________________________________________________________ can Управление "мусорной корзиной" файлов НАЗНАЧЕНИЕ Перемещает файлы в "мусорную корзину", симулируя их удаление. Это допускает восстановление файлов после их кажущегося удаления. Формат вызова can [-l] [-r] file [file ...] Пример вызова can junk Посылает файл junk в "мусорную корзину" Исходный код для can 1 : 2 # @(#) can v1.0 Maintain file trash can Author: Russ Sage 3 4 CAN=$HOME/.trashcan 5 6 if [ ! -d $CAN ] 7 then mkdir $CAN 8 fi 9 10 if [ "`echo \"$1\"|cut -c1`" = "-" ] 11 then case $1 in 12 -l) echo "$CAN:" 13 ls -al $CAN 14 exit 0;; 15 -r) echo "removing $CAN/*:" 16 rm -rf $CAN/* 17 exit 0;; 18 -z|-?) echo "usage can [-l] [-r] file [file ...]" >&2 19 exit 0;; 20 esac 21 fi 22 23 mv $@ $CAN Переменные среды выполнения CAN Положение каталога "мусорной корзины" HOME Положение вашего регистрационного каталога Описание Зачем нам нужен can? По большому счету система UNIX, при всем ее великолепии, является просто структурой для накопления и манипулирования данными в файлах. Как мы отмечали раньше, эта система включает сотни файлов. Некоторые файлы вы желаете хранить неопределенно долго, в то время как другие отслужили свое и создают беспорядок на диске. К несчастью, легко выб- росить то, что в действительности вы хотели сохранить. Команду rm со- вершенно не украшает то, что она является печью для сжигания мусора: бросьте что-нибудь в нее и оно пропадет (если только вы не имеете ко- пии, а восстановление копии - это трудоемкая работа). Вот несколько классических примеров неверного применения команды rm: rm * /tmp <-- Удалить все файлы в каталоге /tmp Мы хотели сказать rm /tmp/*, а на самом деле произошло сначала удаление всех файлов в текущем каталоге, а затем попытка удалить /tmp. Последнее будет безуспешным, поскольку tmp - это каталог. В результате мы удалили все, что хотели сохранить, и сохранили все, что хотели уда- лить! Этот синтаксис похож на другие операторы UNIX, вроде "grep * file": противная ошибка. rm -rf / tmp <-- Удалить каталог tmp со всеми файлами Мы хотели сказать rm -rf /tmp, но нечаянно вставили пробел в ко- манду. На самом деле удалятся ВСЕ файлы во всей системе (если мы дадим команде выполняться достаточно долго), потому что мы сказали UNIX уда- лить корневой каталог и всех его потомков! Вы должны быть внимательны с командой rm. Если покажется, что что-то не так, удалите эту команду. Она может погубить вас. Одна такая ошибка может испортить вам целый день. После того, как это случится, вы станете осторожным на некоторое время, потом внимание ослабнет. Если вы не будете бдительным, ошибки вернутся, чтобы пресле- довать вас. Для нас "мусорная корзина" более желательна, чем печь для сжигания "мусора". Используя этот путь, вы можете вернуться и восстановить то, что вы выбросили по ошибке. Вы также хотели бы контролировать, когда появится мусоросборщик, захватит и окончательно удалит "мусор". Вы мо- жете периодически просматривать содержимое "мусорной корзины", а затем очищать корзину, когда вы уверены, что вы не хотите ничего в ней сохра- нять. Нельзя допускать, чтобы корзина была слишком заполнена, потому что она занимает дисковое пространство. Что делает can? Командный файл can предназначен для управления "мусорной корзиной" ваших файлов. Используя утилиту, вы можете свести к минимуму случайные потери во время работы и даже впоследствии восстанавливать файлы при необходимости. Can не только помещает ваши файлы в "мусорную корзину", но и пока- зывает вам, что в ней в настоящее время находится и очищает ее, когда вы этого хотите. Can распознает только ключи -l и -r. Ключ -l показывает, что нахо- дится в "мусорной корзине", а -r удаляет все ее содержимое. Запомните, что если вы что-то удалили из "мусорной корзины", вы не сможете его восстановить. Процесс помещения файлов в "мусорную корзину" выполняется командой mv. Ключи, предназначенные для can, должны быть первым аргументам в ко- мандной строке. Если вы желаете передать ключи команде mv, то их можно поместить в любом месте командной строки. Единственные ключи, дающие синтаксическую подсказку, - это -z и -?. Их предназначение - быть фла- гами только для обработки ошибок. Благодаря наличию специальных флагов обработки ошибок, выдающих справочную (help) информацию, ключи команды mv, как и ключи can, можно помещать первыми в командной строке, не ока- зывая влияния на can. Если вы создаете ваши командные файлы так, чтобы эти ключи всегда выдавали информацию об использовании (т.е. никогда не были "настоящими" ключами), то вы имеете хороший способ получения помо- щи по синтаксису. Многие (но, увы, не все) стандартные команды UNIX да- ют по ключам -z или -? подсказку об использовании и это полезно помнить всякий раз, когда вы попали в тупик. Если can не получает никаких ключей, действие по умолчанию заклю- чается в пересылке всех указанных файлов в "мусорную корзину", разме- щенную в вашем регистрационном каталоге под именем $HOME/.trashcan. Если этот каталог отсутствует, он автоматически создается при первом выполнении командного файла can. Это позволяет вам запускать команду, не указывая специального положения "корзины". Если вы применяете ключ -r, файлы в "мусорной корзине" будут удалены, а сама она нет. Примеры 1. $ can *.c Перемещает все файлы, которые оканчиваются на .c, в "мусорную кор- зину". 2. $ can -l Выдает список всех файлов, размещенных сейчас в "мусорной корзи- не". 3. $ can -r Удаляет все файлы из "мусорной корзины". 4. $ can -q * Передает ключ -q команде mv. Поскольку это недопустимый ключ ко- манды mv, она выдает сообщение об ошибке и завершается. Пояснения Строка 4 устанавливает место "мусорной корзины" так, чтобы она размещалась в вашем регистрационном каталоге под именем .trashcan. За- метьте, что ее именование, начиная с точки, делает ее нераспечатывае- мым, или скрытым файлом. Единственный способ увидеть такие файлы - использовать ключ -a в команде ls. Строки 6-8 проверяют, определен ли сейчас каталог "мусорной корзи- ны". Если нет, он создается. Обратите внимание, что поскольку его соз- даете вы, он имеет такие права доступа на чтение и запись, как в вашем регистрационном каталоге. Строки 10-21 проверяют, начинается ли первый позиционный параметр с черточки (-). Если такой параметр обнаружен, проверяется, является ли он ключом командного файла can (-l, -r, -z или -?). Обратите внимание, что для того, чтобы для использования двойных кавычек внутри двойных кавычек (строка 10), вы должны экранировать кавычки. Символ обратной косой черты (\) использован именно для этой цели. Если указан ключ -l, выдается напоминание об имени каталога "мусорной корзины", команда ls выводит список файлов в "мусорной корзи- не" и процедура can завершается, поскольку требовалось только вывести список. Если указан ключ -r, выдается сообщение об имени каталога очищае- мой "мусорной корзины" и файлы в ней удаляются командой rm. Это разру- шительная вещь и удаляет ваши файлы навсегда. После удаления can завер- шает работу. Вы можете дополнить программу процедуры так, чтобы давать подтверждение перед выполнением команды, если это позволит вам чувство- вать себя более спокойно. Если указан ключ -z или -?, выдается подсказка об использовании и can завершается. Это не совсем хорошо, но мы не можем использовать сим- вол *, соответствующий любому другому ключу, поскольку ключ может быть предназначен для команды mv, а не для can. Благодаря использованию все- го двух аргументов для обработки ошибок, мы можем разрешить передачу всех остальных аргументов. Если ключ не является одним из ключей can, или одним из указанных ключей обработки ошибок, то он передается коман- де mv. Если ключ недопустим для этой команды, команда mv выдает свое сообщение об ошибке и завершает работу. Вы можете, естественно, модифи- цировать командный файл так, чтобы он проверял допустимость ключей ко- манды mv на "внешнем" уровне. Тогда он может выдать сообщение об ошибке и завершиться, если указанный ключ недопустим ни для can, ни для mv. Вопрос в том, стоит ли платить за более полный контроль над обработкой ошибок ценой разбухания программы и временем исполнения. Строка 23 выполняет собственно перемещение файлов в "мусорную кор- зину". Заметьте, что это выполняется только если не указаны никакие ключи can, поскольку это поведение can, принятое по умолчанию. Здесь используется параметр $@. Путем включения всех параметров в командную строку, любые ключи, предназначенные команде mv, передаются ей. Таким способом мы можем изменить путь, которым файлы посылаются в "мусорную корзину". 3.2.3. dosflp - копирование файлов с гибкого диска формата MS-DOS с использованием символов шаблона в именах файлов ------------------------------------------------------------------- Имя: dosflp _____________________________________________________________________ dosflp Копирование файлов с гибкого диска формата DOS с использованием символов шаблона в именах файлов НАЗНАЧЕНИЕ Копирует файлы с гибкого диска в формате DOS (в XENIX) на жесткий диск. Обеспечивает возможность использования записи с помощью симво- лов-шаблонов для имен файлов на гибком диске, где такая запись обычно недопустима. ФОРМАТ ВЫЗОВА dosflp [-a] [-c] [-dDRIV] [-eEXP][-h] [-l] [-r] [-sDIR] где -a означает копирование файлов, соответствующих *.asm -c означает копирование файлов, соответствующих *.c -d выбирает имя устройства DRIV из набора A,B,X,Y (по умолчанию A) -e использует выражение EXP, чтобы применить к файлам grep -h копирует файлы, соответствующие *.h -l только выдает список файлов -r удаляет файлы вместо их копирования -s указывает подкаталог DIR на гибком диске формата DOS Пример вызова dosflp Копирование всех файлов с устройства A: в текущий каталог Исходный код для dosflp 1 : 2 # @(#) dosflp v1.0 Wildcard copies from DOS floppy Author: Russ Sage 3 4 EXP=.\* 5 DRIVE="A:" 6 OP="c" 7 8 if [ "$#" -gt 0 ] 9 then for ARG in $@ 10 do 11 case "$ARG" in 12 -a) EXP='.*\.asm$';; 13 -c) EXP='.*\.c$';; 14 -d*) DRIVE="`echo $ARG | cut -c3-`:";; 15 -e*) EXP='`echo $ARG | cut -c3-`';; 16 -h) EXP='.*\.h$';; 17 -l) OP="l";; 18 -r) OP="r";; 19 -s*) DRIVE="$DRIVE`echo \"$ARG" | cut -c3- `/";" 20 *) echo "dosflp: arg error" 21 echo "usage: dosflp [-a] [-c] [-d] [-e] [-h] [-l] [-r] [-s]" 22 exit 1;; 23 esac 24 done 25 fi 26 27 case $OP in 28 c) echo "\nCopying files from $DRIVE to `pwd`";; 29 l) echo "\nListing files on $DRIVE" 30 dosdir $DRIVE | more 31 exit;; 32 r) echo "This option removes all the data on the floppy." 33 echo -n "Do you want to do this (y/n): " 34 read RSP 35 if [ "$RSP" = "y" ] 36 then echo "\nRemoving files on $DRIVE" 37 else exit 38 fi;; 39 esac 40 41 dosls $DRIVE | tr "[A-Z]" "[a-z]" > /tmp/doslist 42 43 for FILE in `grep "$EXP" /tmp/doslist` 44 do 45 echo $FILE 46 case $OP in 47 c) doscp $DRIVE$FILE .;; 48 r) dosrm $DRIVE$FILE;; 49 esac 50 done 51 52 rm /tmp/doslist Переменные среды выполнения ARG Хранит аргументы командной строки DRIVE Устройство с гибким диском формата DOS EXP Выражение, имитирующее действие символа-шаблона FILE Хранит имя файла, над которым производится действие OP Ключ, определяющий необходимое действие Описание Зачем нам нужен dosflp? Это команда только для системы XENIX. Операционная система XENIX, являясь продукцией фирмы Microsoft, имеет средства для общения с файло- вой системой MS-DOS. Для ознакомления с основами совместного использо- вания DOS и XENIX давайте рассмотрим основные параметры. Каждый жесткий диск может иметь максимум четыре раздела. Это огра- ничение MS DOS, которое перенесено в мир XENIX. Ничего плохого в этом нет, пока мы не начинаем работать с жестким диском большой емкости. Для 70-мегабайтного диска, например, вы можете создать четыре рав- ных раздела, каждый из которых содержит приблизительно 17 Мбайт. Вы мо- жете создать меньший раздел, но тогда другой раздел должен быть больше. В зависимости от того, какая часть ваших программ и данных должна быть использована в основном MS-DOS и какая - XENIX, может быть использована различная конфигурация. Большим преимуществом системы XENIX/DOS является то, что XENIX мо- жет размещаться в одном разделе, а DOS в другом. Как это сделать? Нужно запустить программу "fdisk" в каждой операционной системе. Это значит, что XENIX может общаться с разделом DOS, получая полное имя устройства, указывающее на другой раздел. Драйвер, который читает раздел DOS, дол- жен знать, как выглядит DOS (т.е. знать файловую систему DOS). Если вы- полнить такую операцию, можно получать списки файлов и копировать их туда и обратно. К сожалению, DOS не имеет возможности чтения разделов XENIX. При работе с гибким диском вы имеете дело только с одним разделом. Это снова ограничение DOS. Некоторые системы UNIX, в отличие от DOS, позволяют иметь столько разделов на жестком или гибком диске, сколько вы хотите, в отличие от DOS. По определению, гибкий диск DOS сформати- рован в системе DOS, которая выполняет форматирование низкого уровня и помещает файловую систему DOS на гибкий диск. В системе XENIX гибкий диск может быть либо в формате файловой системы, либо неструктурированным устройством последовательного доступа подобно магнитной ленте. Для процедуры dosflp мы используем только гиб- кие диски в формате DOS. Теперь к делу. Предположим, вы имеете систему DOS и файлы, находя- щиеся на диске DOS, вы можете читать и писать файлы на гибкий диск из XENIX. Но существуют некоторые ограничения на выполнение операции копи- рования, которые не слишком удобны пользователю. Например, вы можете сказать "doscp *.c a:". В результате все файлы текущего каталога кото- рые оканчиваются на .c, будут скопированы на гибкий диск формата DOS на устройстве a:. Побочный эффект выполнения doscp заключается в том, что все символы перевода строки (или прогона строки) превращаются в символ возврат каретки/перевод строки, поскольку DOS обрабатывает конец строки иначе, чем XENIX. Таким же образом, когда вы копируете с гибкого диска формата DOS в XENIX, лишние символы возврата каретки убираются. Что вы не можете сделать, так это сказать "doscp a:*.c". Команда doscp не допускает указания вида *.c при копировании с гибкого диска. Это происходит потому, что командный процессор распространяет метасим- волы (*,?,[]) и не может непосредственно читать раздел DOS. Поэтому вы не можете использовать символы при копировании с гибкого диска DOS. Отметим, что может наблюдаться гораздо больше побочных эффектов, когда вы имеете дело с гибкими дисками DOS. Во-первых, длина имени фай- ла ограничена. DOS допускает до восьми символов имени файла плюс три символа расширения. В результате после копирования всех ваших файлов XENIX на гибкий диск многие из них могут иметь не те имена, которые они имели в XENIX. Это сущее страдание, когда вы пытаетесь сделать копию на гибкие диски DOS, потому что вы больше не имеете уверенности, как обра- щаться к файлам, когда вы копируете их обратно с гибкого диска. Кроме того, поскольку расширение имени файла в DOS имеет только три символа, файл с именем "spreadsheet.finance" может оказаться на гибком диске DOS с именем "spreadsh.fin" и распознавание его может представлять опреде- ленные трудности. Но это еще не все. Когда файл копируется из XENIX в DOS, ВСЕ имена в DOS записываются заглавными буквами. Если у вас есть файлы с именами, в которых смешаны верхний и нижний регистры, то вы несколько потеряете понятность имен. Если вы используете в именах символы верхнего регистра при копировании файлов обратно в XENIX, они не переводятся на нижний регистр. В результате все имена ваших файлов оказываются записанными символами верхнего регистра в XENIX, что не очень удобно. В чем мы нуждаемся, так это в таком средстве, которому мы можем указывать, какие файлы копировать с гибкого диска на жесткий диск, и которое копирует их с сохранением регистра в имени файла. Все это дела- ет процедура dosflp. Что делает dosflp? Dosflp пытается исключить все негативные аспекты копирования фай- лов XENIX/DOS. Это высокое требование, но оно достижимо. Вкратце подход dosflp следующий: получить список имен файлов с гибкого диска, пере- вести имена в нижний регистр, выбрать из полного списка имена тех фай- лов, которые соответствуют вашим требованиям, и затем копировать файлы один за другим в текущий каталог XENIX. Для того, чтобы сделать это, требуется гораздо больше команд XENIX вида dosxx, а также различных других команд XENIX. В дополнение к копированию, dosflp также выдает список файлов, ко- торые имеются на гибком диске DOS, и удаляет файлы с гибкого диска. Эти функции легко реализовать, потому что как только один раз процедура доступа написана, добавить новые команды для выполнения операций над файлами довольно просто. Обычно мы хотим управлять файлами определенного типа как группой. Сюда относятся ассемблерные исходные файлы, исходные файлы на языке C и файлы-заголовки на языке C. Поэтому, чтобы снять с вас обязанности по вводу универсальных символов для этих типов файлов, мы прямо указываем их в качестве опций команды dosflp. Например, ключ -a копирует только файлы, которые оканчиваются на .asm, поэтому нет необходимости помнить вид выражения для копирования этих файлов. Аналогично, ключ -c копирует все файлы, оканчивающиеся на .c, и ключ -h копирует файлы, оканчивающи- еся на .h. Как мы увидим позже, прямое указание, о котором мы говорим здесь, являеется выражением для команды grep. Использование всех возможностей команды grep достигается при указании образцов имен файлов. Используйте ключ -d для указания, с какого гибкого диска произво- дится копирование. По умолчанию это устройство a: или A:. Не имеет зна- чения, на каком регистре вы укажете имя устройства. Для уверенности проверьте файл /etc/default/msdos. Этот файл содержит соответствия меж- ду символом устройства и маршрутным именем XENIX. Например, файл может выглядеть так: A=/dev/fd048ds9 B=/dev/fd148ds9 C=/dev/hd0d D=/dev/hd1d X=/dev/fd096ds15 Y=/dev/fd196ds15 Как вы видите, маршрутные имена - это обычные имена устройств и ничего больше. В качестве основного средства выполнения работы dosflp использует команду doscp. Это утилита способна понимать формат файловой системы DOS. Dosflp передает ей обозначение устройства и другие опции посредством переменных командного процессора. Например, ключ "-dB:" ме- няет устройство на B вместо принятого по умолчанию устройства A. Если выражения прямого указания типа файлов не соответствуют тому, что вам нужно, вы можете определить свои собственные выражения со- поставления, используя ключ -e. Напомним, что выражение должно соот- ветствовать синтаксису команды grep. Если вы хотите освежить свою па- мять, посмотрите grep(1) в руководстве по AT&T UNIX или grep(C) в руко- водстве по XENIX. Для получения полной информации о синтаксисе посмот- рите ed(1). Этот синтаксис является основой большинства команд, работа- ющих с регулярными выражениями, таких как sed и grep. Например, если вы используете выражение "*test*", выражение для grep должно иметь вид ".*test.*". Его можно слегка изменить в зависи- мости от того, что вы желаете иметь с каждой стороны цепочки test. В данном случае синтаксис указывает все символы (.*), за которыми следует цепочка t-e-s-t, а затем любая цепочка символов (.*). В этом случае ключ имел бы вид "-e.\*test.\*". Это кажется немного странным, но это соответствует синтаксису. (Двойные кавычки не являются частью команды.) Символ обратной косой черты (\) используется для экранирования звездоч- ка. Если вы не экранируете ее, командный процессор соотнесет ее с име- нами всех файлов вашего текущего каталога, чего вы не желаете. Экрани- рование ее позволит, чтобы нужный символ был передан dosflp, для использования ее в grep-последовательности. Ключ -h - это еще один из ключей прямого указания. Давайте вкратце рассмотрим его синтаксис внутри dosflp. Это ".*\.h$", и он указывает любой символ, за которым стоит одно или несколько вхождений любого сим- вола (.*), литеральная точка (.\), символа h и вслед за ним конец стро- ки (h$). Вы могли бы указать то же самое, используя ключ -e, но -h де- лает это гораздо легче. Ключ -l изменяет основное действие команды dosflp. Вместо копиро- вания файлов он выдает список файлов. Это делается путем выполнения различных команд вида dosxx, в данном случае dosdir. Ключ выдачи списка полезен в dosflp, потому что вы можете получить список как информацию к решению о том, что делать дальше, и вам нет необходимости помнить ко- манду dosdir. Ключ -r также изменяет основную операцию команды dosflp. В этом случае файлы удаляются, а не копируются. Если вы указали этот ключ, вы- дается сообщение, которое просит вас подтвердить, что вы хотите удалить указанные файлы. Вы можете просто ответить "n", и запретить удаление, если вы ввели этот опцию случайно. Напомним, что удаленные файлы или файлы, включенные в список (в случае ключа -l), выбраны выражением grep, которое жестко запрограммировано или указано пользователем. По умолчанию выбираются ВСЕ файлы. Для ключа -r это соответствует тому, что сказать "rm *". Последний ключ, -s, обеспечивает возможность доступа к файлам, ко- торые размещены внутри подкаталога на гибком диске DOS. Если вы обраща- етесь только к имени устройства, по умолчанию ключ -s относится к ката- логу самого верхнего уровня на гибком диске. Если нужный вам файл нахо- дится в подкаталоге, вы должны использовать определенную нотацию, чтобы попасть в него. Одно из различий между XENIX и DOS заключается в симво- ле, используемом для разделения элементов маршрутного имени. XENIX использует обычную запись в стиле UNIX - /x/y/z. В DOS применяется сим- вол "обратная косая черта", т.е. \x\y\z. Но если вы хотите использовать команды XENIX на гибком диске DOS, вы должны применять обычную запись XENIX, a:/x/y/z. Это не совсем понятно, но правильно. По умолчанию, dosflp копирует файлы с гибкого диска в ваш текущий каталог на жестком диске. Если вы измените операцию на выдачу списка или удаление, эта операция будет произведена на гибком диске. Примеры 1. $ dosflp -dB: -c -l Выдает список всех файлов вида *.c на гибком диске DOS, размещен- ном в устройстве B. В этом случае не происходит переход вниз в подката- логи, а включаются лишь файлы, размещенные на верхнем уровне каталогов. 2. $ cd /destdir $ dosflp -ssrc -e.\*src.\* Переход в каталог, куда будут помещены файлы. Копируются файлы с гибкого диска DOS (устройство A, подкаталог src), в текущий каталог. Файлы для копирования указаны как *src*. В записи UNIX это выглядело бы так: "cp A:/src/*src* .". 3. $ dosflp -r -stmp Удаляет все файлы, размещенные в подкаталоге tmp на гибком диске DOS (устройство A). Обратите внимание, что сам каталог не удаляется. В записи UNIX это выглядело бы так: "rm A:/tmp/*". 4. $ sh -x `path dosflp` -dB: Запускает процедуру dosflp в отладочном режиме выполнения. Единственное ограничение при таком вызове командного процессора заклю- чается в том, что файл данных, который вы посылаете ему (в данном слу- чае dosflp), должен иметь полное маршрутное имя. Поскольку командный процессор НЕ выполняет поиск маршрутного имени файла, нам необходимо сперва найти маршрутное имя dosflp, затем передать его командному про- цессору, запущенному в отладочном режиме выполнения, а также передать процедуре dosflp аргумент в командной строке. Заметьте, что вызов dosflp таким путем не меняет значение переменной $#, которое только распознает ключ -dB: как аргумент. Пояснения Строки 4-6 выполняют инициализацию по умолчанию путем сохранения значений в соответствующих переменных командного процессора. По умолча- нию символ-шаблон ставится в соответствие всем файлам, указанным выра- жением для команды grep .\*. Обратная косая черта требуется для экрани- рования звездочки, поэтому она не перехватывается командным процессо- ром. Устройство по умолчанию - A:. Операция по умолчанию - копировать файлы, что указано значением "c" для переменной опции. В строках 8-25 устанавливаются значения ключей и производится про- верка на наличие ошибок. Если командная строка имеет некоторые аргумен- ты ($# -gt 0), мы перебираем каждый аргумент и проверяем его. Если най- ден допустимый ключ, переменные устанавливаются согласно ключу. Если обнаружен недопустимый ключ, выдается сообщение об ошибке и программа завершается с плохим статусом возврата. Имеется два важных типа ключей. Ключи, которые выполняют прямое указание типа файла, просто устанавливают переменную EXP в соответствии с ключом. Аналогично, ключи, которые определяют, какой вид работы будет выполняться процедурой, просто устанавливают соответствующую переменную OP. Другие ключи должны обрабатываться путем извлечения одного или нескольких символов из командной строки, которые следуют за флагом клю- ча, эхо-отображения и конвейерной пересылки текущего аргумента ARG ко- манде cut для извлечения символа (символов), начинающихся с третьего символа аргумента, затем присвоения результата этой операции соот- ветствующей переменной. Из всего сделанного следует вывод, что пробелы между ключами и символами, которые стоят за ними, не допускаются. Например, ключ -d должен получить имя устройства. По синтаксису должно быть -dB:, но не -d B:, потому что B: интерпретировалось бы как другой аргумент ARG в цикле for, а это все испортит. В строках 27-39 операция, которая должна быть выполнена, определя- ется при помощи следующего оператора case. Если должно быть выполнено копирование, выдается сообщение "copying" и выполняется то, что следует за оператором case. Если должен быть выдан список файлов, выдается сообщение об устройстве, содержимое которого должно распечататься, за- тем выдается список файлов путем выполнения команды dosdir и конвейер- ной пересылки результата команде more, после чего dosflp завершается. Если файлы должны быть удалены, пользователю выдается запрос на подтверждение удаления. Если ответ "yes", выдается сообщение, с какого устройства файлы будут удалены. Если ответ "no", dosflp завершается. Остаток командного файла имеет дело с механизмом копирования. Строка 41 - это первый шаг в наведении моста над пропастью между двумя типами носителей. Команда dosls использована для получения полного списка файлов с гибкого диска. Перед тем как мы передадим этот список во временный файл, мы пропустим его через команду tr (translate), кото- рая преобразует все символы на нижний регистр, чтобы при копировании файлов их имена были в нижнем регистре. В результате копии будут поме- щены на диск XENIX с именами файлов в нижнем регистре. Если у вас есть файлы с именами в верхнем регистре или в смеси регистров, вы должны вручную исправить их после копирования. Строки 43-50 выполняют само копирование. Цикл for запускается для доступа к каждому файлу индивидуально. Это требование команд вида dosxx. Вы должны получать доступ к одному файлу один раз, поскольку этот уровень не обладает возможностью указания символа-шаблона. Имена файлов, которые использует цикл for, определены путем использования ко- манды grep для выбора имен соответственно выражению, установленному ра- нее. Имя каждого выбранного файла сначала отображается, так что пользо- ватель может видеть, выполняется ли команда так, как ожидалось. В этом месте мы можем сделать одну из двух вещей: или копировать файлы, или удалить их. Эта операция определяется оператором case в строках 46-49. Если операция - копирование файлов, файлы копируются из комбинации уст- ройство-файл в текущий каталог. Обратите внимание, что в переменную DRIVE включается подкаталог, если он был указан в командной строке. Это объясняет наличие символа "/" в конце присвоения значения переменной DRIVE в строке 16. Полное выражение должно быть таким: B:/subdir/file. Если операция - удаление файлов, комбинация устройство/файл удаляется выполнением команды dosrm. Попутно заметим, что маршрутное имя есть нечто гибкое (или небрежное, в зависимости от того, как вы смотрите на него) в том смысле, что вы можете сказать A:/subdir или A:subdir. Оба варианта правильны. После того как все файлы будут обработаны, времен- ный файл удаляется. ВОЗМОЖНЫЕ МОДИФИКАЦИИ КОМАНДНОГО ФАЙЛА Одно из мест, где вы можете настраивать dosflp, это регулярные вы- ражения. Уже включены выражения для .asm, .c и .h, но вы можете изме- нить это или добавить больше ключей для любой последовательности, кото- рую вы часто используете. 3.3. Средства получения резервных копий 3.3.1. autobkp - автоматичеески наращивамый файл резервной копии --------------------------------------------------------------------- Имя: autobkp _____________________________________________________________________ autobkp Автоматически наращиваемый файл резервной копии НАЗНАЧЕНИЕ Производит поиск по дереву файлов, которые изменялись за последние 24 часа, и пересылает их в другую систему (посредством uucp) или пере- мещает их в другую область жесткого диска. ФОРМАТ ВЫЗОВА autobkp [-c] [>logfile] -c копирует файлы в другое место диска вместо использования uucp Пример вызова autobkp < filelist >> bkplog Копирует все файлы, указанные в filelist, и записывает имена файлов в файл с именем bkplog Командный файл autobkp 1 : 2 # @(#) autobkp v1.0 Automatic file backup Author: Russ Sage 3 4 if [ $# -gt 1 ] 5 then echo "autobkp: argument error" >&2 6 echo "usage: autobkp [-c] [>logfile]" >&2 7 exit 8 fi 9 10 if [ "$1" = "-c" ] 11 then COPY=on 12 else COPY=off 13 fi 14 15 echo "\nBACKUP DATE `date '+%a %m/%d/%y %H:%M:%S'`" 16 echo "-----------------------------------------" 17 18 SYSTEM='' # destination system uucp node name 19 : ${SYSTEM:=`uuname -l`} 20 21 echo "Sourse system:\t\t`uuname -l`\nDestination system:\t$SYSTEM" 22 23 while read SRCDIR DESTDIR FILES 24 do 25 if [ ! -d $SRCDIR ] 26 then echo "autobkp: $SRCDIR is not a directory" 27 continue 28 fi 29 30 cd $SRCDIR 31 echo "\nFinding files in: $SRCDIR" 32 33 for FILE in `find . -type f -ctime 0 -name "$FILES" -print` 34 do 35 case $COPY in 36 off) uucp $FILE $SYSTEM!$DESTDIR;; 37 on) cp $FILE $DESTDIR;; 38 esac 39 echo " Transferred $FILE to $DESTDIR" 40 done 41 done Переменные среды выполнения COPY Флаг, определяющий, используется команда uucp или cp FILE Имя каждого файла, найденного в исходном списке маршрутов FILES Символ-шаблон, указывающий, какие файлы определены PATH1 Имя маршрута-источника PATH2 Имя маршрута-приемника SYSTEM Имя системы-приемника для uucp Описание Зачем нам нужен autobkp? Как мы заметили, файлы в UNIX плодятся как кролики. Чем больше файлов мы создаем, тем сильнее желание сохранять их упорядоченными. До- вольно легко стать ленивым или получить ложное представление о безо- пасности и пренебречь регулярным копированием. Вы можете подходить к копированию файлов несколькими путями. Наи- более популярной стратегией является выполнение наращиваемого копирова- ния, когда вся система копируется с некоторой начальной даты (и иногда повторно с регулярными интервалами, но не часто). При коротких интерва- лах (обычно ежедневно) файловая система проверяется на наличие файлов, которые были модифицированы или добавлены за последние 24 часа. Такие файлы копируются, поэтому копия в целом поддерживается такой, какой яв- ляется система в настоящее время. Где размещать копируемые файлы - это еще один интересный вопрос, зависящий от конфигурации вашей системы, количества доступного прост- ранства и важности данных. Давайте рассмотрим некоторые возможности. Автономная микро- или супермикросистема может иметь всего один жесткий диск. Если диск содержит достаточно места для размещения друго- го раздела, вы можете копировать в этот раздел. Раздел может также использоваться как неструктурированное устройство в отличие от файловой системы и рассматриваться как магнитная лента или гибкий диск. Среди других возможностей хранения информации могут быть второй жесткий диск, кассетная лента или устройство копирования на ленту. Если вам недоступ- на ни одна из этих возможностей, вы всегда можете копировать на гибкие диски. Это утомительная ручная работа, но она может быть выполнена при помощи команд tar или cpio. Если вы также имеете доступ к другой, большей системе, такой как общий главный компьютер, вы можете копировать файлы, посылая их в эту систему посредством команды uucp. Даже если вы имеете достаточно места в вашей собственной системе для сохранения ваших копий, у вас может быть очень сильное желание послать копии всех важных файлов в главную машину, потому что это даст вам выносную копию за пределами вашего места расположения. Пожары, наводнения и др ются. Нам необходим механизм, который обычно запускается автоматически (по команде cron или с помощью процедуры at, описанной в главе 5). Сна- чала он обнаруживает все файлы, которые были изменены в последние 24 часа (надеемся, что вы уже имеете первоначальную копию всего). Он начи- нает искать файлы из указанных каталогов и копировать подходящие файлы в указанные каталоги-приемники. Он копирует файлы, используя утилиты, которые наилучшим образом соответствуют используемой вами конфигурации. Все эти вещи выполняются нашим командным файлом autobkp. Что делает autobkp? Вы перечисляете маршруты и autobkp находит файлы по этим маршрутам и копирует их в то место, которое вы указали. Вы можете указывать имена файлов по образцам, таким как *.c, *.h или каким-либо еще. С помощью autobkp вы можете копировать важные файлы без копирования всех файлов. Иногда это удобно - пропускать файлы при копировании. Типичные файлы, которые вы, возможно, не хотите копировать, - это очень большие файлы (не являющиеся важными, как файл core и файлы данных), временные файлы (как *.o, которые вновь создаются при каждой новой компиляции) и испол- няемые файлы, если у вас есть исходные программы на языке Си и вы може- те их скомпилировать для получения новых исполняемых файлов. Пропуская эти файлы, вы можете уменьшить размер ваших копий на мегабайты. По умолчанию копирование производится командой uucp, которая пред- полагает, что у вас подчиненная система по отношению к главной машине и копирует ваши файлы в большую систему. Если вы хотите копировать ваши файлы в другое место жесткого диска или на другой жесткий диск, исполь- зуйте ключ -c для копирования командой cp вместо использования команды uucp. Во время процесса копирования на стандартный вывод выводятся сооб- щения о состоянии дел. Это позволяет легко собрать все сообщения путем переадресации stdout на время копирования. Если вы выполняете autobkp вручную, сообщения выводятся на экран. Первое сообщение - это заголо- вок, который печатает день, дату и время. Это выглядит так: -------------------------- | BACKUP DATE Fri 05/23/86 17:33:35 | Второе сообщение определяет систему-источник и систему-приемник. Оно появляется ниже. В нашем примере система-источник - russ, а систе- ма-приемник - vax. -------------------------- | Source system: russ | Destination system: vax При каждом входе в систему-источник выдается следующее сообщение: ----------------------------- | Finding files in: src_dir | где выражение src_dir - это место, откуда файлы будут переданы в цикл копирования. Обратите внимание, что первое имя должно быть именем каталога, потому что autobkp начинает именно с этого места поиск фай- лов. Если первое имя не является каталогом, программа печатает сообще- ние об ошибке и продолжает работу со следующим набором источник/прием- ник для копирования. Для каждого найденного файла печатается следующее сообщение после завершения копирования: ------------------------------ | Transferred file to dest_dir | которое указывает, что файл file был скопирован в каталог-приемник с именем dest_dir. Файл со списком маршрутов Чтобы сделать интерфейс настолько гибким, насколько это возможно, autobkp читает стандартный ввод. Переназначая stdin, вы можете поддер- живать разные списки файлов, которые необходимо копировать и переклю- чать их в командной строке. Вы можете иметь один список маршрутов для системных файлов, другой для исходных файлов, третий для личных файлов, четвертый для файлов с готовым продуктом и так далее. Для каждой из этих групп файлов создается список маршрутов и передается в качестве входа для autobkp. Входные данные читаются как три поля: FROM, TO и TYPE. Поле FROM - это каталог-источник. Поиск файлов начинается с этого места. Напомним, что autobkp проходит вниз до конца дерева файлов, на- чиная с указанного каталога. Поле TO - это каталог-приемник, куда все файлы, найденные для дан- ной записи в файле со списком маршрутов, помещаются на машине-приемнике или в разделе-приемнике. Поле TYPE - это описатель-шаблон, который сообщает autobkp, какие файлы искать. Его значение может быть *, *.c, *src*, и так далее. Как мы увидим позже, этот описатель передается команде find Unix, которая фактически и выполняет поиск файлов. Вы можете использовать любое выра- жение в поле TYPE, если оно соответствует синтаксису find. Итак: все файлы, которые были изменены в последние 24 часа, обна- руживаются в списке FROM с помощью описателя TYPE и копируются в об- ласть TO. Ниже приводится типичный файл со списком маршрутов. Он указывает несколько каталогов, в которых производится поиск файлов. Обратите вни- мание, что эти каталоги находятся под регистрационным каталогом: если вы хотите скопировать ВЕСЬ регистрационный каталог полностью, вы можете указать этот каталог, но здесь мы хотим выбрать только указанные ката- логи. /usr/russ/bin /pack1/russ/.bkp/bin * /usr/russ/doc /pack1/russ/.bkp/doc * /usr/russ/src /pack1/russ/.bkp/src *.c /usr/product1 /pack1/russ/.bkp/product1 *.[ch] Эти строки копируют каталоги bin, doc и src на локальной машине автора. В случае каталога src мы указали, что копировать нужно только исходные файлы на языке Си. Будет также скопирована некоторая полезная информация из другого места этой же системы. Будут скопированы только файлы с расширением *.c и *.h. Место назначения (прямо указанное в командном файле автоматическо- го копирования) - другая система UNIX. Место назначения - некоторый смонтированный диск, регистрационный каталог, подкаталог копий (bkp). Использование cron Теперь, когда процедура autobkp знает, что искать, давайте скажем ей, когда искать. Cron, вечный резидентный хранитель времени, может легко выполнить эту работу. Входные данные для cron обычно устанавлива- ются системным администратором (или кем-либо, кто имеет права записи в /usr/lib/crontab), так что вы должны попросить администратора устано- вить для вас вход в файл данных cron. Для получения дополнительной ин- формации о входных данных cron, прочтите cron(1M) в Руководстве адми- нистратора. Коротко говоря, полями в файле /usr/lib/crontab являются минута, час, день месяца, месяц и день недели. Используя *, мы можем установить принудительно многие из этих полей во все возможные значе- ния. Входные данные для cron, копирующие мой регистрационный каталог в 4.00 утра каждый день каждой недели каждого месяца года, выглядят так: 0 4 * * * /usr/russ/bin/autobkp.cron Обратите внимание, что вход в cron вызывает управляющую процедуру вместо того, чтобы непосредственно использовать autobkp. Имеется несколько важных причин, чтобы написать процедуру на базе утилиты autobkp. Во-первых, cron не печатает диагностическую информацию на ваш терминал, поэтому если что-нибудь идет не так, вы никогда об этом не узнаете. Во-вторых, проще поддерживать усеченную версию autobkp, а зву- ковые предупреждения добавлять в управляющую процедуру. Вы можете сде- лать собственные модификации управляющей программы и не беспокоиться об отсутствии сообщений от самой утилиты. Управляющую программу можно настолько усложнить, насколько вы желаете. Представленная здесь вполне работоспособна, но легко может быть дополнена. # Cron-driven autobkp driver echo "backed up: `date`" > /dev/tty00 /usr/bin/autobkp < /usr/russ/bin/autobkpath >> /usr/russ/bin/autobkp.log Этот драйвер выдает сообщение на терминал, запускает autobkp, использует для ввода файл со списком маршрутов в каталоге bin и помеща- ет все выводные сообщения в файл протокола. Отметим, что имя терминала дано как абсолютное (tty00). Это правильно только в том случае, когда в вашей системе имеется такой терминал. Использование этого имени терми- нала позволяет сообщению появиться на экране даже если никто на нем не зарегистрирован. Это хорошо, потому что первое, что вы сможете увидеть утром на вашем экране - это сообщение. Если у вас нет указанного терми- нала, вы можете сделать что-то другое, например, передачу самому себе почтового сообщения. Примеры 1. $ autobkp Запускает программу без передачи ей файла со списком маршрутов и без файла протокола. Поскольку поля FROM, TO, TYPE ищутся в стандартном вводе, введите их вручную. Когда вы нажмете возврат каретки, autobkp выполнит указанные действия, напечатает информацию на экран терминала и будет ожидать дальнейшего ввода. Для завершения выполнения командного файла введите ^d (в результате оператор read вернется с ненулевым ста- тусом). 2. $ autobkp < pathlist Получает все входные данные из файла со списком маршрутов, но пе- чатает всю протокольную информацию на экран терминала. Autobkp заверша- ется, когда прочитает все данные в файле pathlist. 3. $ autobkp >> logfile Как и в первом случае, списки маршрутов должны быть введены с кла- виатуры. Все выходные данные выводятся в файл протокола, а не на экран. Для завершения autobkp введите ^d. 4. $ autobkp -c < pathlist >> logfile Копирует файлы из одной области жесткого диска в другую (опреде- ленную каталогом-приемником в файле pathlist). Берет все входные данные из файла pathlist и выводит все выходные данные в файл logfile. Пояснения Строки 4-8 выполняют проверку на наличие ошибок. Autobkp может быть вызван либо без указания опций, либо с одной опцией (-c, при использовании cp). Вспомните, что переназначение ввода-вывода НЕ прини- мается во внимание при рассмотрении аргументов, потому что командный процессор интерпретирует символы переназначения и то, что следует за ними, до вызова команды. Таким образом, если количество позиционных па- раметров больше одного (#1 -gt 1), получаем ошибочное условие. Затем выдается сообщение об ошибке и синтаксическая подсказка и программа за- вершается. В строках 10-13 проверяется использование ключа -c. Обратите вни- мание, что мы не проверяем, равен ли параметр $# единице и не пытаемся выделить первый символ, чтобы посмотреть, равен ли он "-". Это потому, что такая проверка приведет к ошибке, если не указан никакой ключ (что является верным синтаксисом, как указывалось ранее). Если мы сказали if [ $1 = -c ] и не указали ключей, то команда проверки не сработает и будет вы- дано сообщение о том, что "no argument in the statement" ("в операторе нет аргументов"). Но если мы выполним экранирование, например, так: if [ "$1" = "-c" ] то кавычки допускают нулевое значение аргумента, так что проверка правильно оценит недостающее значение $1 как "равен ли нуль -c?" Это даст результат "ложь", поэтому все хорошо. Попутно давайте внимательно рассмотрим работу команды проверки. Вы можете выполнить проверку значения двумя способами. Первый - сравнение строк, а второй - числовое сравнение. Переменные командного процессора ВСЕГДА хранятся в виде строк. Вы можете, тем не менее, заставить систе- му рассматривать эти последовательности как числа и интерпретировать их значения как числовые, подобно оператору number = val(STRING$) языка Бейсик. Вы можете сказать системе, чтобы она изменила свой способ рассмотрения символьных строк путем изменения синтаксиса операции срав- нения. Для символьных строк сравнение выглядит так: str1 = str2 а числовое сравнение выглядит так: num1 -eq num2 -lt -gt Сверьте это с руководством. Если вы попытаетесь смешать символьное сравнение с числовым, сравнение не будет работать. У меня забрало много месяцев программирование на командном процессоре, пока наконец я заме- тил это незначительное различие. Если не рассматривать подробно что-ли- бо подобное, то такие технические ошибки кажутся неуловимыми, но можно найти объяснения, почему что-нибудь работает не так. Вернемся к возможности проверки кода. Если был передан ключ -c, переменная COPY устанавливается, что значит "Да, мы собираемся копиро- вать командой cp, а не использовать uucp". Если ключ -c не использу- ется, переменная COPY не устанавливается. В строках 15-16 печатается заголовочное сообщение о том, что будет выполняться копирование. Обратите внимание, что мы спрятали команду date системы UNIX внутри оператора echo, сократив число перехваченных данных, которые мы должны иметь, чтобы получить дату непосредственно. Проследите за кавычками в этом операторе. Внешние кавычки являются двойными для того, чтобы упаковать весь аргумент для оператора echo. Знаки ударения (`) обрамляют команду date так, что она является "выпол- няемой внутри" и ее выходное сообщение перехватывается для наших нужд. Одинарные кавычки внутри команды date используются для передачи форма- та, который изменяет внешний вид значений так, чтобы заголовок выглядел более красиво. В конце оператора echo кавычки следуют одна за другой. Это не представляет проблемы, поскольку во вложенности нет никакой двусмысленности. Вы должны помнить, что нужно следить за ситуацией, когда вы и командный процессор можете расходиться во мнениях, т. е., когда вы должны обращаться к записи вида "\". В строке 18 переменной SYSTEM присваивается имя удаленной системы, в которую вы будете копировать командой uucp. Здесь она равна нулю, что позже вызовет выполнение другой операции для обеспечения функционирова- ния по умолчанию. Если же вы хотите всегда копировать на вполне опреде- ленную систему, модифицируйте эту строку, чтобы назначить имя этой системы. Если оставить строку 18 так, чтобы она назначала ноль, строка 14 поймает это значение и присвоит переменной SYSTEM имя вашей текущей системы. Другими словами, если вы оставите строку 18 так, как она есть, и вызовете autobkp без ключа -c, вы будете копировать командой uucp са- ми на себя, что вполне допустимо. Однако, из соображений эффективности вы, вероятно хотели бы выполнить autobkp -c для получения локальной ко- пии. Строка 19 иллюстрирует концепцию, часто используемую при програм- мировании на командном языке. Давайте вкратце рассмотрим ее. Первый символ - это ":". В данном случае мы интересуемся, что про- исходит при проверке, а не возвращаемым значением, поэтому мы заставили холостую команду ("не делать ничего") получать результат как аргумент. Текст, следующий за двоеточием, интерпретируется так: "Если переменная SYSTEM не установлена или установлена в ноль, присвоить ей значение, которое следует за ней". В данном случае значение - это выход команды uuname -l. Эта команда устанавливает, что система-приемник является той же системой, что и исходная, если система-приемник не была прямо указа- на ранее. Мы используем uuname -l, а не стандартное выражение uname -n по причине совместимости. Uname -n правильно получает имя узла из структу- ры uts ядра операционной системы, но не все системы XENIX используют элемент узла в виде структуры uts ядра системы. Вместо этого они посы- лают имя в файл /etc/systemid, который соответствует микросети (micnet), разработанной для XENIX фирмой Microsoft. Команда uuname -l - это локальное имя (или исходная машина) для системы uucp. Эта команда возвращает правильное значение и в UNIX, и в XENIX. Имеет смысл исполь- зовать то, что всегда работает! Строка 21 печатает имя исходной системы и системы-приемника. Это сообщение добавляет информацию в запись о том, что собирается делать autobkp, поэтому вы можете видеть по выходным данным, как вы установили данный командный файл. Снова мы спрятали команду uuname внутри операто- ра echo. У нас нет необходимости сохранять имя исходной системы, поскольку оно нам всегда доступно при помощи команды uuname. Поскольку мы всего два раза используем это имя, то решили не использовать для не- го какую-либо переменную. Строки 23-41 - это полный цикл, который управляет автоматическим копированием. Управляющим циклом является оператор while, который чита- ет значения из стандартного ввода. Заметьте, что вы можете считать несколько значений в операторе read. Это удобно, если вы хотите читать более одного значения, но не должны выделять каждую порцию входных дан- ных для того, чтобы определить, является это первым, вторым или третьим элементом данных. Мы читаем их все сразу и они присваиваются указанным переменным. Поскольку выполняется чтение стандартного ввода, мы можем перенаправить stdin при вызове autobkp и оператор read никогда не узна- ет, чем они отличаются. Если мы не переназначаем входные данные, мы должны вводить их с клавиатуры. Цикл завершается при чтении конца файла - в данном случае конец файла со списком маршрутов или символа control-d (^d) с клавиатуры. Поэтому управляющий цикл работает так: "пока еще есть данные для чтения, читать их, обрабатывать, затем читать следующие." Строки 25-28 проверяют, является ли каталог-источник действительно каталогом. Если нет, выдается сообщение об ошибке и оператор continue приводит к следующей итерации цикла while. В строке 30 производится смена каталога на каталог-источник. Вот почему выходные данные команды find являются относительными к точке (.). Если бы мы не выполнили команду cd, то полное имя стало бы абсо- лютным, что могло бы отразиться на системе-приемнике. Тогда маршрут, начинающийся с каталога-приемника, имел бы вниз от себя лишний абсолют- ный путь. Строка 31 печатает каталог, в котором ищутся исходные файлы. Хоро- шо иметь их в файле протокола, поскольку вам легче будет читать и сле- дить, где в данный момент работает autobkp. Строки 33-40 выполняют непосредственно копирование файлов. Здесь циклом является цикл for, который читает имена файлов из выхода команды find. Заметьте, что это автоматически ограничивает общее число файлов, которые может обрабатывать цикл. Этот факт ранее был объяснен в этой книге, но давайте рассмотрим его еще раз. Если find выдает список, состоящий из сотен файлов, то список слов оператора for переполняется и нарушает работу вашего командного процессора (или по крайней мере ко- манды find). Здесь принято допущение, что вы не хотите иметь так много файлов в исходном каталоге. Вы можете избежать этого, разбивая исходный каталог на более мелкие части и пересылая их в файл pathlist. Если вы хотите создать действительно хороший цикл, измените его, например, так: find . -type f -ctime 0 -name "$FILES" -print | while read FILE Благодаря использованию такого цикла, число имен файлов теперь можно изменить от входных ограничений для командного процессора до раз- меров канала системы (который очень большой, практически неограничен- ный). Изменение этой одной строки не оказывает влияния на другие части цикла. Давайте рассмотрим детально команду find. Во-первых, мы указали ей поиск файлов в текущем каталоге (.). Это делает все полные имена от- носительными по отношению к точке. Затем мы сказали команде find найти все файлы типа f, что означает обычные файлы, а не каталоги или файлы устройств. Мы не хотим копировать такие файлы. Дальше мы говорим ей найти файлы, которые были изменены. Под "изменением" мы подразумеваем доступ или модификацию. (Посмотрите в описании stat(2), какие команды изменяют доступ, изменяют и модифицируют время. Говоря "делать поиск для нахождения "ctime 0"", мы имеем в виду все файлы, измененные за последние 24 часа. Объяснения, которые документация по find дает по по- воду этих чисел, довольно непонятны, поэтому отнеситесь к ним с недове- рием.) Затем мы говорим команде find "найти только те файлы, которые определены путем соответствия их имен маршрутным именам, указанным в переменной $FILES, значение которой мы читаем". В этом месте мы можем отфильтровать файлы, которые нам не нужны (как объяснялось предвари- тельно) или выбрать файлы, которые нам нужны. В конце мы говорим коман- де find "напечатать имена всех файлов, которые соответствуют пере- численным критериям". Затем имена файлов передаются в цикл for. Другими словами, выходные данные команды find становятся аргументом для охваты- вающего цикла for. В строках 35-38 оператор case определяет, какого рода копирование мы собираемся делать, и запускает команды копирования. Если переменная COPY не установлена, мы копируем файлы командой uucp. Обратите внима- ние, что местом назначения является SYSTEM. Если мы оставили SYSTEM в нуле в строке 18, то SYSTEM - это наша собственная система и мы копиру- ем командой uucp файлы к себе. Если COPY установлена, то независимо от значения SYSTEM мы копируем (но не командой uucp) файлы в другой ката- лог текущей системы. Этот каталог может быть на том же жестком диске или в другой смонтированной файловой системе. После того, как файл ско- пирован, выдается сообщение, которое говорит о том, какой файл и куда был передан. Удобно иметь в файле протокола эту информацию, поскольку мы имеем возможность проследить, куда были пересланы ваши скопированные файлы. Цикл find выполняется до тех пор, пока не скопируются все файлы в текущем сегменте дерева. Напомним, что команда find рекурсивная, поэто- му убедитесь, что вы указывали не больше деревьев, чем вы хотели. Если вы указали "копировать, начиная с корня (/)", то может быть передан каждый файл, имеющийся в системе. Когда цикл for выполнился, внешний цикл while идет к следующей итерации. Когда все входные данные обрабо- таны, программа завершается. Некоторые особенности uucp Когда используется uucp, в маршруте приемника должен быть установ- лен бит разрешения выполнения ("x") для группы "others" (остальные) для всех промежуточных каталогов, ведущих к файлу. Это будет выглядеть так: --------x Самый последний каталог должен иметь права доступа вида "wx", что- бы uucp могла писать файл в каталог. После этого владельцем файла счи- тается uucp. Если собственником файла хотите быть вы, скопируйте его (используя cp, а не mv) с другим именем и он будет вашей собствен- ностью. Если вы переименуете его командой mv, вы только измените имя, связанное с тем же индексным описателем файла (inode). Но если вы ско- пируете его командой cp, вы создадите новый отмеченный описатель файла. Этот новый описатель файла (созданный вами) имеет ваши идентификатор пользователя (uid) и идентификатор группы (gid), поэтому вы владеете им. Если вы находитесь в корне системы и копируете файл (используя cp, а не mv) поверх другого существующего файла, информация в описателе файла не изменяется, а меняются только данные, доступ к которым указывает описатель файла. Когда uucp устанавливает предшествующие права доступа к файлу на всех промежуточных каталогах такими, что все имеют право записи, последний каталог НЕ будет иметь защиты. Предоставление любому пользо- вателю права записи означает, что кто угодно может удалить или изменить файлы в этом каталоге. Не каждый хочет давать всем это право. Если же вы копируете файлы в обычную область команды uucp общего доступа (/usr/spool/uucppublic/$LOGNAME), то вы должны внимательно следить за ними. Многие системы имеют запускаемые с помощью cron программы, произ- водящие в данном каталоге поиск файлов, к которым не было доступа в те- чение определенного количества дней, и удаляют такие файлы - это вредит вашим копиям. Если период хранения больше, чем промежуток между вашим копированием, у вас может быть все в порядке. Как и многое другое, это зависит от ваших обстоятельств и требований безопасности. Усовершенствования В оригинале файл со списком маршрутов имеет аргумент TYPE в конце аргумента FROM, например /usr/russ/bin/*. Это представляет проблему (кроме того, что показывает, что ваш автор еще не является мастером!), потому что когда символ * будет выделен, он будет расширен в имена всех файлов вместо того, чтобы трактоваться как литеральный символ. Простое решение - использовать отдельные поля, что и было сделано. Мастерским решением является экранировать метасимвол для сохранения его как лите- рального символа. Как только символ * будет выделен из маршрутного име- ни, символ \ представит его в виде * вместо того, чтобы дать его на расширение. Например, можно написать так: TYPE=`basename \"$FROM"` Здесь символ * присваивается переменной TYPE, вместо того, чтобы присвоить TYPE список всех файлов, которые соответствуют метасимволу. Затем, когда будет вызвана команда find, переменная TYPE должна быть экранирована так, чтобы метасимвол интерпретировался не командным про- цессором, а самой командой find. 3.3.2. cpiobr - копирование и восстановление файлов в виде потока данных ------------------------------------------------------------------- Имя: cpiobr ____________________________________________________________________ cpiobr Копирование и восстановление в виде потока данных командой cpio НАЗНАЧЕНИЕ Обеспечивает интерфейс в виде меню с командой cpio и удобства при копировании и восстановлении файлов. Выходные данные на носитель копи- руются в виде потока данных. ФОРМАТ ВЫЗОВА cpiobr Пример вызова cpiobr Вызывает главное меню для копирования, восстановления или выдачи списка файлов Командный файл cpiobr 1 : 2 # @(#) cpiobr v1.0 Cpio stream backup and restore Author: Russ Sage 3 4 if [ "$#" -gt "0" ] 5 then echo "cpiobr: too many arguments" 6 exit 7 fi 8 9 while : 10 do 11 c 12 set `date` 13 echo " 14 15 $1, $2 $3 $4 16 17 Cpiobr Backup & Restore 18 ----------------------- 19 Backup to removable media 20 Restore from removable media 21 List files on media 22 Long list files on media 23 to exit 24 25 Press b,r,f,l or : \c" 26 27 read CMD 28 if [ "$CMD" = "" ] 29 then break 30 fi 31 32 ABORT=off 33 34 while : 35 do 36 echo " 37 38 Enter media type: 39 Raw System V floppy drive (/dev/rfp021) 40 Raw XENIX floppy drive (/dev/rfd0) 41 Tape drive (/dev/rmt0) 42 Any device (/dev/???) 43 to exit 44 45 Press s,x,t,a, or : \c" 46 47 read MEDIA 48 case $MEDIA in 49 s|S) DEV=/dev/rfp021 50 break;; 51 x|X) DEV=/dev/rfd0 52 break;; 53 t|T) DEV=/dev/rmt0 54 break;; 55 a|A) echo "enter full pathname (or <> to exit): \c" 56 read DEV 57 if [ "$DEV" = "" ] 58 then continue 59 else break 60 fi;; 61 "") ABORT=on 62 break;; 63 *) echo "cpiobr: invalid command \"$MEDIA\"";; 64 esac 65 done # while get media 66 67 if [ "$ABORT" = "on" ] 68 then continue 69 fi 70 71 case $CMD in 72 b|B) echo "\nEnter the source directory name: \c" 73 read SRC 74 cd $SRC 75 echo "\nPlace floppy in drive and hit ...\c" 76 read CMD 77 find . -print | sort | cpio -ocBv > $DEV 78 echo "\nhit \c" 79 read CMD 80 ;; 81 r|R) echo "\nEnter the destination directory name: \c" 82 read DEST 83 cd $DEST 84 echo "\nPlace floppy in drive and hit ...\c" 85 read CMD 86 cpio -icBvdmu < $DEV 87 echo "\nhit \c" 88 read CMD 89 ;; 90 f|F) cpio -icBt < $DEV 91 echo "\nhit \c" 92 read CMD 93 ;; 94 l|L) cpio -icBtv < $DEV 95 echo "\nhit \c" 96 read CMD 97 ;; 98 *) echo "cpiobr: invalid command \"$CMD\"" 99 ;; 100 esac 101 done Переменные среды выполнения ABORT Флаг, определяющий, делать ли аварийное прекращение CMD Команда, получаемая от пользователя DEST Каталог-приемник при восстановлении DEV Маршрутное имя устройства носителя MEDIA Хранит тип устройства, которое будет использоваться SRC Каталог-источник при копировании Описание Зачем нам нужен cpiobr? Мы уже получили представление об удобстве и управлении копировани- ем с помощью команды autobkp, но мы еще не имели дела с неструктуриро- ванными устройствами. Это такие устройства, которые не содержат файло- вую систему, а просто имеют данные, которые записаны на них в виде по- тока данных. В таком качестве используются магнитные ленты и иногда гибкие диски. Как указывалось ранее, у вас может отсутствовать дисковое пространство или размещенная в другом месте система для копирования в формате файловой системы. Вместо этого вам может потребоваться исполь- зовать комплект гибких дисков или магнитную ленту. Даже если у вас име- ются другие возможности для копирования, может наступить время, когда копия на магнитной ленте или гибких дисках может быть оправдана как до- полнительная мера предосторожности, поскольку впоследствии вы можете восстановить ленту или гибкие диски в другом месте. Проблема заключается в том, что имеется широкий набор версий син- таксиса команды cpio для такого копирования, которые зависят от формата и используемого устройства. Если вы переключаете устройства, вы должны запомнить (или должны посмотреть) соответствующий синтаксис. Одним из решений является прямое указание различных вариаций команды cpio в тексте программы и вызов их в ответ на меню, которое просто спрашивает пользователя, какого типа носитель должен быть использован. Это наш подход при написании cpiobr. Другое преимущество системы меню заключа- ется в том, что вы можете приспособить рутинную работу по выполнению такого рода копирования для неопытного оператора или канцелярского ра- ботника, которым требуется знать только лишь, как монтировать магнитную ленту или другой носитель и отвечать на вопросы меню. Что делает cpiobr? Cpiobr - это управляемая с помощью меню интерактивная утилита ко- пирования и восстановления. На самом деле это интерфейс с командой cpio системы UNIX. Функции, предоставляемые меню, включают копирование фай- лов с жесткого диска на гибкий диск, восстановление файлов с гибкого диска на жесткий диск, выдачу списка имен файлов, хранимых на гибком диске и выдачу списка файлов с необязательной дополнительной информаци- ей (подобно ls -l). Гибкий диск здесь является первичным устройством назначения, но могут использоваться и другие носители, такие как маг- нитная лента большой емкости или кассетная магнитная лента (streamer). После выбора типа операции, которая должна быть выполнена, нужно выбрать тип используемого устройства. Утилита Cpiobr может быть исполь- зована на устройствах системы UNIX фирмы AT&T (/dev/fp021), устройствах системы XENIX фирмы IBM (/dev/fd0), стримерной ленте (/dev/rmt0) или любом другом устройстве по вашему желанию (/dev/???). Обычно имя уст- ройства определяет тип используемого носителя. Поскольку эта утилита предназначена для всех машин UNIX, некоторые из вариантов могут отсутствовать в вашей машине, поэтому вы имеете право выбрать любое имя устройства, которое вам необходимо. Как только имя устройства выбрано и, если вы выполняете копирова- ние или восстановление, вам задается вопрос, что является катало- гом-источником или каталогом-приемником. Укажите имена каталогов, начи- ная с вашего текущего каталога или абсолютное полное имя, начиная с корня (/.), после чего cpiobr переходит в этот каталог и затем исполь- зует относительные полные имена с этого места. Тем самым исключаются любые проблемы, связанные с тем, что абсолютное полное имя становится частью самой копии. Если вы даете относительное полное имя, убедитесь в том, что оно начинается от вашего текущего каталога, чтобы cpiobr начал работать с нужного места в дереве файлов. Когда файлы копируются на желаемый носитель, маршрутное имя, пере- данное cpio, начинается с "/.". Это означает, что никакого префикса имени каталога на гибком диске нет. Поэтому при восстановлении файлов обязательно нужно дать полное маршрутное имя. Все файлы, поступающие с гибкого диска, будут помещены прямо в каталог-приемник, который вы ука- зали cpiobr. Примеры (Здесь приводятся ответы на запросы главного меню, подменю и до- полнительная информация, появляющиеся в таком порядке.) 1. b x $HOME Копирует файлы на гибкий диск системы XENIX, начиная с каталога $HOME. 2. r a /dev/rmt0 $HOME Восстанавливает файлы с устройства, выбранного мной (/dev/rmt0, магнитная лента), и помещает файлы в мой регистрационный каталог. 3. l s Выдает в широком формате информацию обо всех файлах, размещенных на гибких дисках системы UNIX машины типа PC. Пояснения В строках 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 Kбайт. Одним из интересных аспектов здесь является то, что когда коман- да 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) обращается к блочным уст- ройствам, таким как жесткий диск, а потоковый формат обращается к нест- руктурированным устройствам (опции -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 3 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 10 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 22 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 Kбайтный файл, содержащий в виде длинного формата список файлов, которые должны были быть скопированы. В действительности, там были два файла, один из которых был отсортирован, а другой нет. Они были одного размера, и 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 3 4 c 5 set `date` 6 echo " 7 8 $1, $2 $3 $4 9 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 16 17 Enter command (1-3,<>): \c" 18 read CMD 19 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 обра- щаться самой к себе позволяет вам добавлять неограниченное число файлов протокола в список, и вам предоставляется свобода по выбору имен таких файлов. Возможно, вы заметили, что стратегия, использованная в командном файле log, может быть использована для обеспечения вывода на экран лю- бого набора файлов (записные книжки, документация или еще что-то). Все, что вам нужно сделать для этого - записать их в соответствии с командой more и добавить столько команд в главное меню, сколько вы хотите. Пояснения Строка 4 очищает экран, используя команду c, представленную ниже в этой книге. (Вместо этого вы снова можете использовать команду clear, если она доступна.) Строка 5 устанавливает в позиционные параметры выход команды date. Это то же самое, что мы делали в программе cpiobr. Строки 6-17 выводят меню. Здесь использован один оператор echo, как описано в cpiobr. Стро- ка 13 читает команду пользователя. Строки 20-27 выполняют основную работу программы. Если введенная команда была просто возвратом каретки (трактуется как нуль), программа завершается. В строке 23 команда sed просматривает файл $HOME/bin/log. Это требует, чтобы вы поместили log в подкаталоге двоичных модулей ва- шего регистрационного каталога. Если вы разместите ее где-либо в другом месте, вы должны изменить эту строку. Команда sed использует ключ -n, который запрещает вывод, за исключением того, что явно указано для пе- чати. Строка -e находит имена файлов. Данный подход использует функцию замены в команде sed. Таким обра- зом мы можем заменить все за исключением имени файла, а затем напеча- тать его. Смысл этой записи примерно такой: сперва мы ищем выражение more (/more/), находя тем самым все строки в файле протокола, содержа- щие слово "more". По определению, каждый файл протокола выводится на экран, используя команду more. Поскольку вы добавляете файлы протокола, каждая новая строка должна содержать слово more, поэтому файлы нахо- дятся автоматически по выражению команды sed. Затем мы указываем команде sed сделать замену. Первое выражение содержит в себе всю строку от начала до конца, но мы применяем круглые скобки для отметки внутри нее образца .*, тем самым выделяя часть стро- ки между пробелом после "more" и первой точкой с запятой в конце стро- ки. Если вы посмотрите на все строки в файле log, которые начинаются с "more", то вы увидите, что это соответствует имени файла, которое мы ищем. Затем мы указываем команде sed заменить всю строку на первый обра- зец "pattern 1". "Pattern 1" - это запись команды sed для первого отме- ченного или "отмеченного биркой" выражения. Другими словами, мы замени- ли имя файла на всю строку целиком и указали команде sed напечатать ре- зультат, тем самым выдавая на экран имя файла. Эта работа выполняется для такого количества операторов more, сколько вы имеете. Чем больше файлов log вы имеете, тем больше файлов обрабатывает команда sed. Обратите внимание, что оператор sed просмат- ривает любое количество символов от начала строки для нахождения слова "more". Не указывая в программе конкретное число символов, на которое нужно отступить, вы получаете тем самым свободу выбора ваших собствен- ных уровней отступа. Если введенная команда не является допустимой, выдается сообщение об ошибке. Эта программа не имеет цикла, поэтому срабатывает один раз. Если вы хотите запустить ее снова, вы должны снова ввести log. Пример $ log 1 После запуска программы выводится меню. Введите число 1 для того, чтобы увидеть все имена log-файлов. Теперь, когда мы изучили, как распознавать и управлять файлами во- обще, давайте рассмотрим некоторые систематические методы управления ИНФОРМАЦИЕЙ в файлах. Мы начинаем в следующей главе с файлов, которые важны для нас как для программистов.