tar ファイルを単に cat でつなげてしまっても GNU の tar なら読めるよ


こんな風に tar ファイルを cat でつなげてしまったとする。

```console
$ 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
```

```console:実行結果
A
B
```

後ろにつなげた C ファイルと D ファイルは認識されてない！
そりゃ単に cat で繋げちゃったら認識しなそうな気もするよね！

## でも GNU tar ならできちゃう

ところがそんな時も GNU tar なら -i (--ignore-zeros) オプションがあるから大丈夫

```console
$ tar -itf ABCD.tar
```

```console:実行結果
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 とは

http://www.gnu.org/software/tar/manual/html_node/Standard.html

> 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 でつなげても大丈夫だよ](http://qiita.com/kitsuyui/items/d877e22d3be1241579e1)
で書いた通り、 gzip は cat でそのままつなげてもちゃんと読める。

この 2 つを組み合わせて考えればわかるが、
つまり tar.gz ファイルを cat でそのままつなげても、 -i オプションさえつければちゃんと認識できてしまうのだ！
(もちろん GNU tar に限定した話)

## 実例

```console
$ 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
```

```console
$ tar -iztf ABCD.tar.gz
```

```console:実行結果
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 には @ という便利な記法があって、

```console
$ tar -cf ABCD.tar @AB.tar @CD.tar
```

のように結合することができる。
この記法のすごいところは tar.gz ファイルであっても @AB.tar.gz のようにそのまま書いて OK
~~あまり使う機会はなさそうだが~~ bz2 と gz と xz を 1 度でつなげることもできる。


# 免責

この情報はいかなる種類の保証も伴わずに「現状のまま」で提供するよ。
筆者はいろいろと責任を負わないし負えないよ。 (ry