お前のtarオプション指定は古い

# はじめに

mattnさんが以下のようなことをつぶやかれていました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">tar コマンドで z フラグを付けるとオッサンだとバレる。</p>&mdash; mattn (@mattn_jp) <a href="https://twitter.com/mattn_jp/status/971192187143708673?ref_src=twsrc%5Etfw">2018年3月7日</a></blockquote>

それに対するリプへのリプ。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">今は自動判定なのです。。</p>&mdash; mattn (@mattn_jp) <a href="https://twitter.com/mattn_jp/status/971193955378319360?ref_src=twsrc%5Etfw">2018年3月7日</a></blockquote>

オッサンでした。
ここら辺の処理はbuffer.cの[check_compressed_archive](https://github.com/Distrotech/tar/blob/release_1_29/src/buffer.c#L373)という関数で行われてます。まあ今回の本題はこちらでないのでこの話はここまで。

その後もオッサン達（失礼）がオプションの話で盛り上がっていました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">さらにオッサンになると<br>tar cf - . | gzip -9 &gt; foo.tar.gz<br>のように別途実行してました。<br>当時使ってたSunOSだかSolarisのtarはzオプションサポートしてなかった気がしますが定かではないです。</p>&mdash; Hiroaki Nakamura (@hnakamur2) <a href="https://twitter.com/hnakamur2/status/971193482093056000?ref_src=twsrc%5Etfw">2018年3月7日</a></blockquote>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">うるせぇな、tarっつったら、xvzfなんだよ。（老害</p>&mdash; Daisuke Maki (anovaさん） (@lestrrat) <a href="https://twitter.com/lestrrat/status/971199896555409409?ref_src=twsrc%5Etfw">2018年3月7日</a></blockquote>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">xzf / xzvf やろ! (戦争勃発</p>&mdash; MURAOKA Taro (@kaoriya) <a href="https://twitter.com/kaoriya/status/971203303949328384?ref_src=twsrc%5Etfw">2018年3月7日</a></blockquote>

ちなみに私が展開するときは以下のように書いてます。

```
$ tar xfz archive.tar.gz
```

さて、ここまで何の疑問も持たずに読んできた人はみんなオッサンです。

# オプションの指定方法

ちょっとマニュアルを見てみましょう。うーん、ウェブで見られるmanはいまいちいいのがないので御自分で`man tar`してください。

さて、xzfなのかxfzなのかはともかくハイフンが付いてない指定方法の記述はありましたか？
・・・ありません。そう、実はハイフンのないオプション指定はOld Styleと言われ古い形式なのですm9(^Д^)ﾌﾟｷﾞｬｰ。今どきの書き方はこうです。

```
$ tar -xzf archive.tar.gz
```

ちなみにこれができるのはGNUのtarでBSDのtarはまた違うかもしれないのですがまあLinuxでの話とします。[^1]
ついでに、manにはありませんがinfoにはOld Styleに関する記述があります。

[^1]: さっきとオプションの順番違くね？と思った方は鋭い。

# Old Styleを指定したときの動作

ところで、ふとOld Styleがどう処理されてるんだろうと気になりました。なお、私好みの指定方法xfzはハイフン付きで指定すると、

```
$ tar -xfz archive.tar.gz
tar: z: Cannot open: No such file or directory
tar: Error is not recoverable: exiting now
```

:sob:
うんまあわかるけど、どちらかというとこっちの振る舞いの方が正しいけど、というわけで私は未だにOld Styleで書いているわけですが[^2]それはさておき、Old Styleが指定されたときの動作です。これを見ると何故「xfz」はよくて「-xfz」は駄目なのかもわかります。

[^2]: ところで何故xfzとしているかというと、tarがzオプション対応してないころに学んだので展開x、ファイル指定f、圧縮されてるからgzipかましてねのzという指定が身についているのです。

該当箇所はtar.cのdecode_options関数の[ここら辺](https://github.com/Distrotech/tar/blob/release_1_29/src/tar.c#L2253-L2308)

何をしているかと言うと、

1. ハイフン付きじゃない指定がされてたら
2. ハイフン付きのオプションにすげかえる
3. その際それぞれのオプションに分離する
4. 後続引数をとるタイプのオプションの場合はまとまりオプションの次の引数を挟み込む

つまり、

```
$ tar xfz archive.tar.gz
```

という指定は以下のようにオプション指定されたものとして以後の処理が行われます。

```
$ tar -x -f archive.tar.gz -z
```

一方、初めからハイフン付きの場合はこのケアは行われません。つまり、

```
$ tar -xfz archive.tar.gz
```

は以下と同様になります。[^3]

[^3]: 初めからハイフン付きの場合はtarソース内では分離は行われません。[argp](http://www.gnu.org/software/libc/manual/html_node/Argp.html)というライブラリが使われておりその中で行われています。

```
$ tar -x -f z archive.tar.gz
```

zというファイルがないとファイルありませんエラーです。

# あとがき

xfz派が救われたのはたまたまだったのかそういう指定をする人が実は多い（からそれを考慮した実装が行われた）のか、ハイフンありオプション形式でないtarの場合はオプション解析がどう実装されているのかなどなど謎は深まるばかりですが、昔から使われているコマンドは互換性を考慮しないといけないという苦労が表れているなと思いました。LinuxというかUNIXのコマンドソースを眺めるのは楽しいですね。