こんな風に tar ファイルを cat でつなげてしまったとする。
$ touch A
$ touch B
$ touch C
$ touch D
$ tar -cf AB.tar A B
$ tar -cf CD.tar C D
$ cat AB.tar CD.tar > ABCD.tar
これを tar の -t オプションでファイルをリストアップしてみると
$ tar -tf ABCD.tar
A
B
後ろにつなげた C ファイルと D ファイルは認識されてない!
そりゃ単に cat で繋げちゃったら認識しなそうな気もするよね!
でも GNU tar ならできちゃう
ところがそんな時も GNU tar なら -i (--ignore-zeros) オプションがあるから大丈夫
$ tar -itf ABCD.tar
A
B
C
D
なんと、 cat でつなげただけの後ろの tar もちゃんと読めるのだ!
残念なことに、この便利なオプションは BSD tar にはないようだ。
普通のやり方で tar を結合するしかない。
仕様
tar ファイルの仕様は以下の URL に書いてある (POSIX.1-1988 と POSIX.1-2001 で規格化)
http://www.gnu.org/software/tar/manual/html_node/Standard.html
歴史的経緯により tar のフォーマットは大きく分けて 3 種類ある。
- V7 Unix の tar (BSD 系のデファクトスタンダード)
- GNU デフォルトの tar (GNU 系のデファクトスタンダード)
- pax フォーマット (比較的新しい規格で、専用コマンド pax があったりする。
あまり使われてない)
このうち pax フォーマットについては、この記事で述べてきた通りの挙動にはならない。残念。
--ignore-zeros とは
Physically, an archive consists of a series of file entries terminated by an end-of-archive entry, which consists of two 512 blocks of zero bytes. A file entry usually describes one of the files in the archive (an archive member), and consists of a file header and the contents of the file. File headers contain file names and statistics, checksum information which tar uses to detect file corruption, and information about file types.
2 * 512 = 1024 byte を tar ファイルの終端マーカーとして置く決まりになっているようだ。
対して man tar すると出てくる --ignore-zeros の説明では
-i, --ignore-zeros Ignore zeroed blocks in archive. Normally two consecutive 512-blocks filled with zeroes mean EOF and tar stops reading after encountering them. This option instructs it to read further and is useful when reading archives created with the -A option.
--ignore-zeros はこの終端マーカーを無視してくれるとのこと。なので cat でつなげて問題ないわけだ!
tar ファイルフォーマットのより詳しい説明が知りたいなら、先に上げた URL を読んでいけばいい。
それなら tar.gz は?
gzip 圧縮したテキストファイルは cat でつなげても大丈夫だよ
で書いた通り、 gzip は cat でそのままつなげてもちゃんと読める。
この 2 つを組み合わせて考えればわかるが、
つまり tar.gz ファイルを cat でそのままつなげても、 -i オプションさえつければちゃんと認識できてしまうのだ!
(もちろん GNU tar に限定した話)
実例
$ touch A
$ touch B
$ touch C
$ touch D
$ tar -zcf AB.tar.gz A B
$ tar -zcf CD.tar.gz C D
$ cat AB.tar.gz CD.tar.gz > ABCD.tar.gz
$ tar -iztf ABCD.tar.gz
A
B
C
D
すごいぞ -i オプション!
もちろん tar -izxf ABCD.tar.gz とすれば、いつもどおり展開できる。
超大量に tar.gz ファイルがあるときに、覚えておいて損はなさそう。
Python でも可
Python の標準ライブラリ tarfile にも同様のオプション ignore_zeros はある。
http://docs.python.jp/3.4/library/tarfile.html
class tarfile.TarFile(name=None, mode='r', fileobj=None, format=DEFAULT_FORMAT, tarinfo=TarInfo, dereference=False, ignore_zeros=False, encoding=ENCODING, errors='surrogateescape', pax_headers=None, debug=0, errorlevel=0)
いいね!
きっと他の言語にも同様のオプションがあるんじゃないかなー。
BSD tar について
このままだと BSD tar に不公平だと思うので、 BSD tar の便利な機能も紹介したい。
BSD tar には @ という便利な記法があって、
$ tar -cf ABCD.tar @AB.tar @CD.tar
のように結合することができる。
この記法のすごいところは tar.gz ファイルであっても @AB.tar.gz のようにそのまま書いて OK
あまり使う機会はなさそうだが bz2 と gz と xz を 1 度でつなげることもできる。
免責
この情報はいかなる種類の保証も伴わずに「現状のまま」で提供するよ。
筆者はいろいろと責任を負わないし負えないよ。 (ry