TL;DR
tar(1)
の引数はオプションではなくkey
だから
歴史
tar(1)
は Unix v7 (1979) で導入されたが、その前身は Unix v4 (1973) の tp(1)
、更にこれは Unix v1 (1971) の tap(1)
に遡る。
80年代に入りSystemV v.s. BSDといったことが起きたりし、PWB/UNIX (Programmer's WorkBench)で導入された cpio(1)
とtar(1)
、どちらがUnixの標準アーカイバか争われた結果、IEEE Std. 1003.1-2001 (POSIX.1-2001) を以って tar(1)
は規格から削除され、代わりに IEEE Std 1003.2-1992 で導入された折衷案のpax(1)
が標準となった。よって、現在実装中立なtar(1)
の仕様書がそもそも存在しない。最後の中立規格は1997―1998年策定のSUSv2 (UNIX V98) の仕様となる。
sccs(1)
はPWB/UNIXが初出。(なぜかこちらは、DEVELOPMENT コマンドという註釈つきで現行の IEEE Std. 1003.1-2017 な POSIX に残っている。)仕様
tap(1)
の頃から一貫して、
NAME tap -- manipulate DECtape
SYNOPSIS tap [ key ] [ name ... ]
DESCRIPTION tap saves and restores selected portions of the
file system hierarchy on DECtape.
[..]
The function portion of the key is specified by
one of the following letters:
r The indicated files and directories,
[..]
と説明がされている。SUSv2 のtar(1)
では、
NAME
tar - file archiver (LEGACY)
SYNOPSIS
tar key [file...]
DESCRIPTION
The tar utility processes archives of files. Its actions are controlled by the key operand.
OPTIONS
None.
OPERANDS
The following operands are supported:
key
The key operand consists of a function letter followed immediately by zero or more modifying letters. The function letter is one of the following:
[..]
となっており、tap(1)
の頃からあまり大差はない。
tar(1)におけるkeyとは。なぜサブコマンドではないのか。
tar(1)
における key というのは r、x、t、u、c いずれかの機能(つまり、Update、eXtract、Createなど)をまず指定し、続けて空白を入れずにfオプションだったりvオプションだったり、挙動を指定するオプション引数を続ける、ひとかたまりの文字列ということになっている
現代ならこれは
tar extract -v -f example.tar
のようにサブコマンド指定とそれに対してのオプション、というように引数を設計するだろう。また、PWB/UNIXでは既に導入されていたsccs(1)
では既にサブコマンドのあるコマンドが導入されている。
しかしながら、全面的にPDP-11のアセンブリで記述されていた Unix v1 の頃からある tar(1)
(の前身)では高度な引数解析を持つ実装が用意されなかったのだろう。それがそのまま、現代にも引き継がれてしまっている。
結果として、tar(1)
はサブコマンドのつもりで一文字目に function letter を指定し二文字目以降にオプション文字を並べる、ひとつの文字列として key string を受け入れる、という他の Unix コマンドとやや毛色の違うオプション仕様になってしまっている。
現代のtar実装
FreeBSD
FreeBSD RELEASE 14.1 の man page https://man.freebsd.org/cgi/man.cgi?tar(1) を見るに、
NAME
tar -- manipulate tape archives
SYNOPSIS
tar [bundled-flags <args>] [<file> | <pattern> ...]
tar {-c} [options] [files | directories]
tar {-r | -u} -f archive-file [options] [files | directories]
tar {-t | -x} [options] [patterns]
function letter であってもハイフンつきのオプションとして、最初のオプションに指定することで挙動を指定するのが正則で、key string での指定は bundled-flags という名前で歴史的互換性のための指定方法ということになっている。
このあたり、function それぞれで指定できるオプションの種類などがmanを一瞥しただけで理解できる書き方になっていてとてもわかりやすくて良い。
なお、-c
指定のときに-f
を指定しなかった場合、/dev/sa0 (FreeBSD)
や/dev/st0 (Linux)
がデフォルト指定されることになっており、現代でも今なお、TapeARchiveというコマンドの由来の残り香がある。
GNU
このあたり、GNU Tar 1.35 (2023/08/22) でも大差はない。https://www.gnu.org/software/tar/manual/html_node/basic-tar-options.html#basic-tar-options
つまり、--create --verbose
や-c -v
などのように、ハイフンつきfunction letterを最初にもってきてその後に個別オプションを指定する、という書き方がまず説明されており、key string はあくまで歴史的互換性で残されているもののようだ。
ただし、--file, -f
についての扱いは FreeBSD とはやや異なる。指定をしなかったときのデフォルト指定はTAPE
環境変数の指定に従うことになっており、この環境変数が指定されていなかった場合の挙動はコンパイル時に設定されているデフォルト設定に従うことになっている。https://www.gnu.org/software/tar/manual/html_node/file-tutorial.html#file-tutorial
たとえば、tar --show-defaults
の実行結果として以下の出力だったとしたとき
$ tar --show-defaults
--format=gnu -f- -b20 --quoting-style=escape
--rmt-command=/etc/rmt --rsh-command=/usr/bin/rsh
デフォルトで -f-
が指定されているので、特に何も指定していなくても勝手に標準入力や標準出力を使ってくれる、ということになる。このあたり、完全に各 distribution で作成されているパッケージのビルドオプション次第ではあるものの、大抵の環境では -f-
が指定されていることが期待できそうな気がする。
追記
Unix v1 のその先の源流をさらに辿ってみた続編を書きました。 https://orumin.blogspot.com/2024/06/tar1-tarkey-arguments.htmlまた、過去ではなく未来方向、つまり Bell Lab で Unix の successor として生まれた Plan 9 や Inferno における tar
についてはこちらの lufia 氏のブログでまとめてもらってます! Plan 9とInfernoにおけるtar(1)の変化