Алексей Федорчук
2001-2005 гг
Архивация и компрессия — это уже не только манипулирование файлами, но и, некоторых образом, изменение их контента. Тем не менее рассмотрим их в этом разделе — ведь с позиций пользователя их смысл близок копированию файлов. И, собственно, целям резервного копирования и архивация, и компрессия призваны служить.
Для пользователя DOS/Windows, привыкшего к программам типа Zip/WinZip, архивация и компрессия неразрывны, как лошади в упряжке. Однако это — разные действия. Архивация — это сборка группы файлов или каталогов в единый файл, содержащий не только данные файлов-источников, но и информацию о них — имена файлов и каталогов, к которым они приписаны, атрибуты принадлежности, доступа и времени, что позволяет восстановить как данные, так и их структуру из архива в первозданном виде. Компрессия же предназначена исключительно для уменьшения объема, занимаемого файлами на диске (или ином носителе).
Для архивации и компрессии предназначены самостоятельные команды. Хотя архивацию и компрессию можно объединить в одной конструкции или представить так, будто они выполняются как бы в едином процессе.
Традиционные средства архивации Unix-систем — команды cpio
и tar
. Суть первой, как можно понять их названия — копирование файлов в файл архива и из файла архива. Используется она в трех режимах.
Первый режим, copy-out, определяемый опцией -o
(или --create
), предусматривает считывание списка файлов (name list) со стандартного ввода и объединяет их в архив, который может быть направлен в архивный файл или на устройство для записи резервных копий. Список файлов для архивирования может представлять собой вывод какой-либо иной команды. Так, в примере
$ find ./* | cpio -o > arch.cpio
файлы текущего каталога, найденные командой find
, при посредстве команды cpio
будут направлены в архивный файл arch.cpio
.
Второй режим (copy-in, опция -i
, или --extract
) осуществляет обратную процедуру: развертывание ранее созданного архива в текущем каталоге:
$ cpio -i < arch.cpio
Здесь нужно заметить, что если разворачиваемый архив включает подкаталоги, автоматически они созданы не будут, и последует сообщение об ошибке. Для создания промежуточных каталогов команда cpio
должна использоваться с опцией -d
(--make-directories
).
В третьем режиме (copy-pass, опция -p
, или --pass-through
) команда cpio
выполняет копирование файлов из одного дерева каталогов в другой, комбинируя режимы copy-out и copy-in, но без образования промежуточного архива. Список файлов для копирования (name list) считывается со стандартного ввода, а каталог назначения указывается в качестве аргумента:
$ cpio -p dir2 < name_list
Команда cpio
имеет множество опций, позволяющих создавать, в частности, архивы в различных форматах (для межплатформенной переносимости). Однако я на них останавливаться не буду, отсылая заинтересованных к соответствующей man-странице: она не кажется мне удобной в применении. И упомянута здесь, во-первых, для полноты картины, во-вторых — универсальности ради (архивы cpio
понимаются абсолютно всеми Unix’ами), в третьих — как одно из средств преобразования пакетов, используемых в различных дистрибутивах Linux, друг в друга. Например, утилита rpm2cpio
преобразует широко распространенный формат пакетов rpm
в еще более универсальный cpio
.
Основным же средством архивирования во всех Unix-системах является команда tar
. Обобщенный формат ее —
$ tar [options] archiv_name [arguments]
где archiv_name
— обязательный аргумент, указывающий на имя архивного файла, с которым производятся действия, определяемые главными опциями. Формы указания опций для команды tar
очень разнообразны. Исторически первой была краткая форма без предваряющего дефиса, что поддерживается и поныне. Однако в текущих версиях команды в целях единообразия утверждена краткая форма с предваряющим дефисом или дублирующая ее полная форма, предваряемая двумя дефисами. Некоторые опции (например --help
— получение справки об использовании команды) предусмотрены только в полной форме.
Главные опции и указывают на то, какие действия следует выполнить над архивом в целом:
- создание архива (опция
c
,-c
или--create
); - просмотр содержимого существующего архива (опция
t
,-t
или--list
); - распаковка архива (опция
x
,-x
,--extract
или--get
).
Легко понять, что при работе с архивом как целым одна из этих главных (т.н. функциональных) опций обязательна. При манипулировании же фрагментами архива они могут подменяться другими функциональными опциями, как то:
r
(или--append
) — добавление новых файлов в конец архива;u
(или--update
) — обновление архива с добавлением не только новых, но и модифицированных (с меньшим значением атрибутаmtime
) файлов;-A
(--catenate
или--concatenate
) — присоединение одного архива к другому;--delete
— удаление именованных файлов из архива;--compare
— сравнение архива с его источниками в файловой системе.
Прочие (очень многочисленные) опции можно отнести в разряд дополнительных — они определяют условия выполнения основных функций команды. Однако одна из таких дополнительных опций — f
(-f
или --file
), значение которой — имя файла (в том числе файла устройства, и не обязательно на локальной машине), также является практически обязательной. Дело в том, что команда tar
(от tape archiv) изначально создавалась для прямого резервного копирования на стриммерную ленту, и именно это устройство подразумевается в качестве целевого по умолчанию. Так что если это не так (а в нынешних условиях — не так почти наверняка), имя архивного файла в качестве значения опции f
следует указывать явно. Причем некоторые реализации команды tar
требуют, чтобы в списке опций она стояла последней.
Проиллюстрируем сказанное несколькими примерами. Так, архив из нескольких файлов текущего каталога создается следующим образом:
$ tar cf arch_name.tar file1 ... file#
Если задать дополнительную опцию v
, ход процесса будет отображаться на экране — это целесообразно, и в дальнейших примерах эта опция будет использоваться постоянно.
С помощью команды tar
можно заархивировать и целый каталог, включая его подкаталоги любого уровня вложенности, причем — двояким образом. Так, если дать команду
$ tar cvf arch_name.tar *
файлы каталога текущего каталога (включая подкаталоги) будут собраны в единый архив, но без указания имени каталога родительского. А командой
$ tar cvf arch_name.tar dir
каталог dir
будет упакован с полным сохранением его структуры.
С помощью команды
$ tar xvf arch_name.tar
будет выполнена обратная процедура — распаковка заархивированных файлов в текущий каталог. Если при архивировании в качестве аргумента было указано имя каталога, а не набора файлов (пусть даже в виде шаблона) — этот каталог будет восстановлен в виде корневого для всех разархивируемых файлов.
При извлечении файлов из архива никто не обязывает нас распаковывать весь архив — при необходимости это можно сделать для одного нужного файла, следует только указать его имя в качестве аргумента:
$ tar xvf arch_name.tar filename
Правда, если искомый файл находился до архивации во вложенном подкаталоге, потребуется указать и путь к нему — от корневого для архива каталога, который будет различным для двух указанных схем архивации. Ну а для просмотра того, каким образом был собран наш архив, следует воспользоваться командой
$ tar tf arch_name.tar
Если архив собирался по первой схеме (с именами файлов в качестве аргументов, вывод ее будет примерно следующим:
dir2/ dir2/file1 example new newfile tee.png
При втором способе архивации мы увидим на выводе нечто вроде
dir1/ dir1/example dir1/new dir1/newfile dir1/tee.png dir1/dir2/ dir1/dir2/file1
В данном примере опция v
была опущена. Включение ее приведет к тому, что список файлов будет выведен в длинном формате, подобном выводу команды ls -l
:
drwxr-xr-x alv/alv 0 10 май 11:03 2002 dir2/ -rw-r--r-- alv/alv 0 10 май 11:03 2002 dir2/file1 ...
Команда tar
имеет еще множество дополнительных опций, призванных предотвращать перезапись существующих файлов, осуществлять верификацию архивов, учитывать при архивации разного рода временные атрибуты, вызывать для исполнения другие программы. К некоторым опциям я еще вернусь после рассмотрения команд компрессии, другие же предлагается изучить самостоятельно, воспользовавшись страницей экранной документации man tar
.
Команд для компрессии файлов несколько, но реальный интерес ныне представляют две парные утилиты — gzip
/gunzip
и bz2
/bunzip2
. Первый член каждой пары, как легко догадаться из названия, отвечает преимущественно за компрессию, второй — за декомпрессию файлов (хотя посредством должных опций они легко меняются ролями).
Команда gzip
— это традиционный компрессор Unix-систем, сменивший в сей роли более старую утилиту compress
. Простейший способ ее использования —
$ gzip filename
где в качестве аргументов будет выступать имя файла. При этом (внимание!) исходный несжатый файл подменяется своей сжатой копией, которой автоматически присваивается расширение *.gz
.
В качестве аргументов может выступать и произвольное количество имен файлов — каждый из них будет заменен сжатым файлом *.gz
. Более того, посредством опции -r
может быть выполнено рекурсивное сжатие файлов во всех вложенных подкаталогах. Подчеркну, однако, что никакой архивации команда gzip
не производит, обрабатывая за раз только единичный файл. Фактически форма
$ gzip file1 file2 ... file#
просто эквивалент последовательности команд
$ gzip file1 $ gzip file2 ... $ gzip file#
Правда, объединение компрессированных файлов возможно методом конкатенации (с помощью команды cat
) или посредством архивирования командой tar
— и о том, и о другом будет сказано чуть позже.
Команда gzip
имеет и другие опции, указываемые в краткой (однобуквенной) или полной нотации. В отличие от tar
, знак дефиса (или, соответственно, двойного дефиса) обязателен в обоих случаях. Так, опциями -1
… -9
можно задать степень сжатия и, соответственно, время исполнения процедуры: -1
соответствует минимальному, но быстрому сжатию, -9
— максимальному, но медленному. По умолчанию в команде gzip
используется опция -6
, обеспечивающая разумный компромисс между скоростью и компрессией.
Благодаря опции -d
(--decompress
) команда gzip
может выполнить развертывание сжатого файла, заменяя его оригиналом без расширения *.gz
. Хотя в принципе для этого предназначена команда gunzip
:
$ gunzip file.gz
Использование этой команды настолько прозрачно, что я задерживаться на ней не буду.
В последнее время широкое распространение получил компрессор bzip2
, обеспечивающий большую (на 10-15%) степень сжатия, хотя и менее быстродействующий. Использование его практически идентично gzip
, с деталями его можно ознакомиться с помощью страницы экранной документации man bzip2
. Итоговый компрессированный файл получает имя вида *.bz2
и может быть распакован командой bunzip2
(или командой bzip2 -d
). Следует только помнить, что форматы *.gz
и *.bz2
не совместимы между собой. Соответственно, первый не может быть распакован программой bunzip2
, и наоборот.
Поскольку программы tar
и gz
обеспечивают каждая свою сторону обработки файлов, возникает резонное желание использовать их совместно. Самый простой способ сделать это — воспользоваться командой tar
с опцией z
. Например, команда
$ tar cvzf dir.tar.gz dir/
Обратите внимание, что суффикс *.gz
в этом случае нужно указывать в явном виде — автоматически оно к имени архива не присоединяется и компрессированный архив будет иметь вид dir.tar
. Поскольку в Unix расширения имен файлов не играют той сакральной роли, что в MS DOS, это не помешает распаковке такого файла командой
$ tar xvzf dir.tar
Опция z
сама по себе никакой компрессии не выполняет — она просто вызывает компрессор gzip
для сжатия каждого из архивируемых файлов. Аналогичный смысл имеет и опция j
— только ею для этой цели привлекается команда bzip2
(в некоторых системах для вызова последней из команды tar
используется опция y
).
При использовании команды tar
с опцией z
(или j
) исходные файлы остаются в неприкосновенности. Следует, однако, помнить, что архив сжатых файлов не может быть обновлен командой tar
с параметрами r
или u
.
Есть и другой способ совместной архивации и компрессии — просто последовательность команд
$ tar cf dir.tar * $ gzip dir.tar
В результате образуется сжатый архив — внешне такой же файл dir.tar.gz
. Хотя в принципе архив сжатых файлов и сжатый архивный файл — это разные вещи (можно заметить, что они даже различаются по объему, хотя и всего на несколько байт), сжатый архив также может быть благополучно развернут командой tar
с опцией z
. И столь же очевидно, что он не может быть ни пополнен, ни обновлен средствами архиватора tar
.
Компрессированные архивы, созданные сочетанием программ tar
и gzip
/bzip2
— общепринятый в Unix-системах метод распространения файлов. Однако иногда для совместимости с ОС, не допускающими двух точек в имени файла (знаете такую ОС?), компрессированным tar-архивам присваивается суффикс *.tgz
. Можно встретить и файлы с маской *.tbz2
(или даже *.tbz
— именно такой вид имеют пакеты в 5-й ветке FreeBSD). Нетрудно догадаться, что это те же архивы *.tar.bz2
.
Резервное копирование
Архивы, как правило, создаются для целей резервного копирования — то есть записи их на какой-либо внешний носитель. В качестве последних в настоящее время практически могут рассматриваться только внешние винчестеры и оптические диски (CD-R/RW и записываемые DVD разных форматов). И потому способы обращения с ними резонно рассмотреть тут же, в интермедии о файловых операциях.
Можно выделить два основных способа резервного копирования — создание точных слепков файловой системы или отдельных ее фрагментов, и запись архивов. Первый способ применяется, например, при переносе системы с одного носителя на другой, второй же — для сохранения данных на внешних носителях.
Обычный способ переноса файловых систем — классическая утилита dd
. Для использования ее в этом качестве достаточно указать файл устройства — источника и файл целевого устройства. Например, директива
$ dd if=/dev/ad0s1a of=/dev/ar0s1a
воспроизведет корневую файловую систему дискового раздела, указанного в качестве первого аргумента, на разделе второго диска. При этом нужно учитывать, что каталоги корневой файловой системы, представляющие точки монтирования самостоятельных файловых систем на отдельных разделах (такими обычно являются /usr
, var
, /home
и так далее), затронуты не будут: для их реплицирования на другом носителе команду dd
придется повторить с указанием соответствующих источников и целевых устройств.
Важно также, что команда dd
не требует ни предварительного создания файловой системы на целевом носителе, ни его монтирования. Ибо механизм ее работы — поблочный перенос всего содержимого устройства-источника на устройство-цель.
В BSD-системах та же задача может быть решена с помощью команды cpdup
. Правда, она требует предварительного создания разделов на целевом носителе, файловых систем на разделах и их монтирования в структуру текущей коревой файловой системы. Вот как используется cpdup
при ручной установке ОС DragonFlyBSD (без помощи программы BSD Installer, описанной в
$ cpdup / /mnt $ cpdup /var /mnt/var $ cpdup /etc /mnt/etc $ cpdup /dev /mnt/dev $ cpdup /usr /mnt/usr
Здесь каталоги /
, /var
и так далее — точки монтирования корня и отдельных его ветвей файловой системы установочного LiveCD, а /mnt
, /mnt/var
— заблаговременно созданные, отформатированные и смонтированные разделы на винчестере, на который инсталлируется DragonFlyBSD.