Архивация и компрессия
Архивация и компрессия - это уже не только манипулирование файлами, но и, некоторых образом, изменение их контента. Тем не менее рассмотрим их в этом разделе - ведь с позиций пользователя их смысл близок копированию файлов. И, собственно, целям резервного копирования и архивация, и компрессия призваны служить.
Для пользователя 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 - получение справки об использовании команды) предусмотрены только в полной форме.
Главные опции и указывают на то, какие действия следует выполнить над архивом в целом:
Легко понять, что при работе с архивом как целым одна из этих главных (т.н. функциональных) опций обязательна. При манипулировании же фрагментами архива они могут подменяться другими функциональными опциями, как то:
Прочие (очень многочисленные) опции можно отнести в разряд дополнительных - они определяют условия выполнения основных функций команды. Однако одна из таких дополнительных опций - 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.