📼

いまさら tar

10 min read 3

tar(1) と tarball

Unix な世界にいると .tar や .tar.gz などの拡張子を持つファイルをよく目にします. これらは複数のファイルをひとまとめにしたファイルアーカイブと呼ばれるファイルで,しばしば tarball と呼ばれます[1]. これはちょうど MS-Windows でいう ZIP ファイルのようなものです.

tarball を操作するには tar(1) を利用します. tar(1) は 1979 年の Version 7 UNIX で登場しました. その名前は tape archive に由来し,当時はその名前の通りテープドライブ相手にファイルをアーカイブするコマンドとして利用されていたようです.

また,tar(1) はどこにでもあるように感じられますが,POSIX コマンドではありません[2]. 実装もまちまちで,システムによってファイルフォーマットが異なるかもしれません. システム間での交換可能性を保ちたいのであれば,POSIX コマンドで tarball を扱える pax(1) を利用するのが良いかもしれません[3]

tar(1) のバージョン

動作を確認した tar(1) のバージョンとデフォルト値は次の通りです.

$ uname -srm
Linux 5.11.0-37-generic x86_64
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.3 LTS"
$ tar --version
tar (GNU tar) 1.30
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by John Gilmore and Jay Fenlason.
$ tar --show-defaults 
--format=gnu -f- -b20 --quoting-style=escape --rmt-command=/usr/sbin/rmt --rsh-command=/usr/bin/rsh

基本の使い方

tar [ key ] [ name ... ]

tar(1) のコマンド書式は上のようになっています. tar(1) の動作は引数 key によって決まります. key は,基本の動作を決定する c, x, t, r, u のいずれか 1 文字と,オプションを指定する文字からなる文字列です. それぞれの動作について紹介していきます.

アーカイブの作成 (c)

tar cf archive file...

アーカイブを作成するには,tar c コマンドを利用します. file... にはアーカイブするファイルやディレクトリを 1 個以上指定します. file... にディレクトリが指定された場合,そのディレクトリの内容が再帰的にアーカイブされます. f のオプションはアーカイブをファイル archive に出力することを指定します[4]

アーカイブ作成の例
$ tar cf hoge.tar hoge/	 # ディレクトリ hoge 以下の全てのファイルを hoge.tar にアーカイブ
$ tar cf archive.tar file1.txt file2.txt  # file1.txt file2.txt を archive.tar に
$ tar cf - foo bar >foobar.tar  # 出力に - を指定すると stdout に出力される

アーカイブの展開 (x)

tar xf archive [member...]

アーカイブを展開するには,tar x コマンドを利用します. member... には展開するファイルやディレクトリを 0 個以上指定します. member... にディレクトリが指定された場合,そのディレクトリの内容が再帰的に展開されます. member... が指定されない場合は,アーカイブに含まれる全てのファイルが展開されます. f のオプションはアーカイブをファイル archive から入力することを指定します.

アーカイブ展開の例
$ tar cf hoge.tar  # hoge.tar の内容を全て展開する
$ tar cf hoge.tar  hoge/fuga/  # hoge.tar からディレクトリ hoge/fuga/ 以下を全て展開
$ tar cf archive.tar file1.txt  # archive.tar から file1.txt のみを展開する
$ cat foobar.tar | tar cf - foo  # 入力に - を指定すると stdin から入力される

アーカイブの内容確認 (t)

tar tf archive [member...]

アーカイブの内容を確認する (アーカイブに含まれるファイル名を表示する) には,tar t コマンドを利用します. member... には確認するファイルやディレクトリを 0 個以上指定します. member... にディレクトリが指定された場合,そのディレクトリの内容が再帰的に表示されます. member... が指定されない場合は,アーカイブに含まれる全てのファイルが表示されます. アーカイブには同じファイルの複数のバージョンが含まれることがあります. その場合には,ファイル名が複数回表示されることがあります.

アーカイブの内容を確認する例
$ tar tf hoge.tar  # hoge.tar の内容を全て表示する
hoge/
hoge/foo.txt
hoge/bar.dat
hoge/fuga/
hoge/fuga/baz.txt
piyo/
piyo/qux.dat
piyo/quux.txt
hoge/fuga/baz.txt
$ tar tf hoge.tar piyo/  # hoge.tar から ディレクトリ piyo/ 以下を表示
piyo/
piyo/qux.dat
piyo/quux.txt
$ tar tf hoge.tar hoge/fuga/baz.txt  # hoge.tar から hoge/fuga/baz.txt のみを表示
hoge/fuga/baz.txt
hoge/fuga/baz.txt

アーカイブに追加 (r)

tar rf archive file...

アーカイブにファイルを追加するには tar r コマンドを利用します. このコマンドは tar c コマンドと似ていますが,既存のアーカイブにファイルを追加します. アーカイブが圧縮されている場合 (.tar.gz などの場合),この操作を行うことはできません.

アーカイブにファイルを追加する例
$ tar tf hoge.tar  # 追加前の hoge.tar の中身
hoge/
hoge/foo.txt
hoge/bar.dat
hoge/fuga/
hoge/fuga/baz.txt
piyo/
piyo/qux.dat
piyo/quux.txt
hoge/fuga/baz.txt
$ tar rf hoge.tar piyo  # hoge.tar にディレクトリ piyo を追加
$ tar tf hoge.tar  # 追加後の hoge.tar の中身
hoge/
hoge/foo.txt
hoge/bar.dat
hoge/fuga/
hoge/fuga/baz.txt
piyo/
piyo/qux.dat
piyo/quux.txt
hoge/fuga/baz.txt
piyo/
piyo/qux.dat
piyo/quux.txt

アーカイブの更新 (u)

アーカイブを更新するには tar u コマンドを利用します. このコマンドは tar r コマンドと似ていますが,アーカイブに含まれていないファイルやアーカイブに含まれているファイルより新しいファイルをアーカイブに追加します. アーカイブが圧縮されている場合 (.tar.gz などの場合),この操作を行うことはできません.

$ tar tf hoge.tar  # 更新前の hoge.tar の中身
hoge/
hoge/foo.txt
hoge/bar.dat
hoge/fuga/
hoge/fuga/baz.txt
piyo/
piyo/qux.dat
piyo/quux.txt
hoge/fuga/baz.txt
$ touch hoge/foo.txt  # ファイルを更新
$ touch hoge/fuga/ababa.txt  # ファイルを追加
$ tar uf hoge.tar hoge  # アーカイブを更新
$ tar tf hoge.tar  # 更新後の hoge.tar の中身
hoge/
hoge/foo.txt
hoge/bar.dat
hoge/fuga/
hoge/fuga/baz.txt
piyo/
piyo/qux.dat
piyo/quux.txt
hoge/fuga/baz.txt
hoge/foo.txt
hoge/fuga/ababa.txt

便利なオプション

処理実行の確認 (w)

tar t を除く操作において,操作を行う前に確認します. 文字 y から始まる単語を入力すると操作が実行されます.

オプション w の例
$ tar cfw hoge.tar hoge piyo
add `hoge'?y
add `hoge/foo.txt'?y
add `hoge/bar.dat'?y
add `hoge/fuga'?n
add `piyo'?y
add `piyo/qux.dat'?n
add `piyo/quux.txt'?y

詳細の表示 (v)

通常,tar(1) は “静かに” 処理をします. オプション v を指定すると処理中のファイル名を表示するようになります.

オプション v の例
$ tar xvf hoge.tar
hoge/
hoge/bar.dat
hoge/foo.txt
hoge/fuga/
hoge/fuga/baz.txt
piyo/
piyo/quux.txt
piyo/qux.dat
hoge/fuga/baz.txt

tar t コマンドとともに指定すると ls -l のような表示になります.

オプション v の例
$ tar tvf hoge.tar 
drwxrwxr-x mkn/mkn           0 2021-10-07 20:56 hoge/
-rw-rw-r-- mkn/mkn        2796 2021-10-07 20:57 hoge/bar.dat
-rw-rw-r-- mkn/mkn         446 2021-10-07 20:56 hoge/foo.txt
drwxrwxr-x mkn/mkn           0 2021-10-07 20:57 hoge/fuga/
-rw-rw-r-- mkn/mkn          16 2021-10-07 20:57 hoge/fuga/baz.txt
drwxrwxr-x mkn/mkn           0 2021-10-07 20:55 piyo/
-rw-rw-r-- mkn/mkn          56 2021-10-07 20:55 piyo/quux.txt
-rw-rw-r-- mkn/mkn        1234 2021-10-07 20:55 piyo/qux.dat
-rw-rw-r-- mkn/mkn          24 2021-10-07 20:58 hoge/fuga/baz.txt

作業ディレクトリの変更 (C)

オプション C を利用すると,処理時の作業ディレクトリを変更することができます.

オプション C の例
$ mkdir dest  # ディレクトリの作成
$ tar xfC hoge.tar dest/  # ディレクトリ dest に移動してから hoge.tar を展開
$ ls -l dest
total 8
drwxrwxr-x 3 mkn mkn 4096 10月  7 16:24 hoge
drwxrwxr-x 2 mkn mkn 4096 10月  7 11:44 piyo
$ tar cfC fuga.tar dest/ hoge/fuga/  # ディレクトリ dest に移動してから hoge/fuga/ を fuga.tar にアーカイブ
$ tar tf fuga.tar 
hoge/fuga/
hoge/fuga/baz.txt
hoge/fuga/ababa.txt

アーカイブの圧縮 (z, Z, j, J, a)

.tar.gz なファイルを作成するには tar cf - file | gzip とコマンドを実行する方法もありますが,tar(1) に組み込みの圧縮機能を利用することもできます. オプション z を指定すると,アーカイブは gzip で圧縮されます. 同様に Z では Compress で, j は bzip2 で,J は xz で圧縮されます. オプション a ではアーカイブの拡張子から圧縮形式を推測してくれます. 圧縮されたアーカイブに対して tar rtar u の操作を行うことはできません.

圧縮されたアーカイブを作る
$ tar cfz hoge.tar.gz hoge/ piyo/  # gzip
$ tar cfj hoge.tar.bz2 hoge/ piyo/  # bzip2
$ tar cfJ hoge.tar.xz hoge/ piyo/  # xz
$ tar cfZ hoge.tar.Z hoge/ piyo/  # Compress (もはや使われまい)
$ tar cfa hoge.tar.gz hoge/ piyo/  # 拡張子から推測して gzip
$ tar cfa hoge.tar.xz hoge/ piyo/  # 拡張子から推測して xz

アーカイブを展開したり内容を確認したりする際にはこれらのオプションを指定する必要はありません (バージョンによっては要求されることもあります).

圧縮されたアーカイブを読む
$ tar tf hoge.tar.gz  # オプション z 無しでも動く
hoge/
hoge/foo.txt
hoge/bar.dat
hoge/fuga/
hoge/fuga/baz.txt
hoge/fuga/ababa.txt
piyo/
piyo/qux.dat
piyo/quux.txt
$ tar xf hoge.tar.gz  # 展開もできる

ファイルの除外 (--exclude=)

オプション --exclude= を利用すると,特定のパターンを含むファイルをアーカイブの対象から除外することができます. 例えば,git のレポジトリを tarball にする際などに便利です.

オプション --exclude= の例
$ ls -la repo/
total 32
drwxrwxr-x  4 mkn mkn 4096 Sep 21 21:07 .
drwxrwxr-x 14 mkn mkn 4096 Oct  7 21:06 ..
drwxrwxr-x  8 mkn mkn 4096 Sep 21 21:07 .git
-rw-rw-r--  1 mkn mkn  430 Sep 21 20:59 .gitignore
-rw-rw-r--  1 mkn mkn 1066 Sep 21 20:59 LICENSE
-rw-rw-r--  1 mkn mkn  197 Sep 21 21:07 Makefile
-rw-rw-r--  1 mkn mkn  191 Sep 21 20:59 README.md
drwxrwxr-x  2 mkn mkn 4096 Sep 21 20:59 src
$ tar cvf repo.tar --exclude='.git*' repo
repo/
repo/Makefile
repo/README.md
repo/LICENSE
repo/src/
repo/src/main.c

おわりに

おわりです.

余談ですが,Ubuntu の tar(1) の日本語版の man page はどうも古いようです (22 September 1993!!). LC_ALL=C man tar と実行して英語版を読むか,man tar と google して JM Project のページを読んだほうが良さそうです. もっとも,tar-doc をインストールして texinfo を読むのが一番良いのですが.

おまけ: tar を利用してディレクトリ構造をコピーする

V7 UNIX の man page には次のようなコマンドが紹介されています.

Tar can also be used to move hierarchies with the command

cd fromdir; tar cf - . | (cd todir; tar xf -)

なんだかとてもトリッキーに見えます. 当時の cp(1) ではディレクトリのコピーができなかったようなので,ディレクトリ構造をコピーする方法として有用だったのかもしれません. 現代の Unix では cp -r で再帰的なディレクトリのコピーが可能です.


参考

  • TAR(1), UNIX PROGRAMMAER'S MANUAL, Seventh Edition, Volume 1, January 1979.
  • Man page of TAR, JM Project, 2019-02-04 更新, 2021-10-06 閲覧.
  • tar, Wikipedia, 2021-10-06 閲覧.
  • Joel Chandler Harris, Uncle Remus: His Songs and His Saying, D. Appleton and Company, 1886. (Wikisource を 2021-10-06 閲覧.)
  • タールぼうや, 福娘童話集, 2021-10-06 閲覧.
  • tar, FreeBSD Manual Pages, The FreeBSD Project, 2020-01-31, 2021-10-17 閲覧.
脚注
  1. また,tarball という名前は,Joel Chandler Harris のアメリカ黒人民話集 “リーマスおじさん” の物語から第二章 “素敵なタールの赤ん坊” に掛けたジョークになっています. この物語には,狐が作ったタールの赤ん坊の罠に掛かった兎がタールまみれになって動けなくなってしまう描写があります. ↩︎

  2. tar(1) の POSIX 規格は ISO/IEC 9945-1:1996 (“POSIX.1”) にはありましたが,IEEE Std 1003.1-2001 (“POSIX.1”) にはありません. ISO/IEC 9945-1:1996 (“POSIX.1”) にもありません. ko1nksm さんのコメントを参照してください. ↩︎

  3. ko1nksm さんのコメントも参照してください. ↩︎

  4. f オプションを指定しない場合,まず環境変数 TAPE が調べられます. この環境変数が設定されている場合は,その値がアーカイブのファイル名として利用されます. さもなければ,tar(1) の実行ファイルに組み込まれたデフォルトの値が利用されます. デフォルトの値は tar --show-defaults で確認できます. ↩︎

Discussion

tar(1) の POSIX 規格は ISO/IEC 9945-1:1996 (“POSIX.1”) にはありましたが

ちょうどこの件に関する情報を調べていたのですが、おそらく ISO/IEC 9945-1:1996 にも tar(1) は無かったと思います。なぜならこれは C 言語 API の規格だからです。

ISO/IEC 9945-1:1996
Information technology — Portable Operating System Interface (POSIX) — Part 1: System Application Program Interface (API) [C Language]

こちらを見ても、シェルとユーティリティが最初に標準化された POSIX.2 (1992) に tar は含まれていません。ただしこちらを見ると以下のように書いてあるため tar 形式については規定されてあった可能性が高いです。

It also defines a format for data interchange.

POSIX (POSIX.1-2001) と統合される前の SUS (Single UNIX Specification) には tar が含まれていましたが、削除されてから POSIX へ統合されました。


システム間での交換可能性を保ちたいのであれば,POSIX コマンドで tarball を扱える pax(1) を利用するのが良いかもしれません.

実際に重要なのは、複数ある tar 形式のどれを使用するかという話で、pax (1) が使用する ustar 形式 または pax 形式(共に POSIX で標準化された歴史的な tar の拡張形式)は、GNU tar や BSD tar も対応しているはずなので、明示的に形式を指定すれば tar(1) を使っても大丈夫だと思います。

tar(1) の POSIX 規格は ISO/IEC 9945-1:1996 (“POSIX.1”) にはありましたが

この部分は BSDTAR(1) の Man page からの引用でした (BSDTAR(1) の Man page を参考にしたことを明記し忘れていることに気が付きました). たしかに,ISO/IEC 9945-1:1996 には tar(1) について書いてなさそうです.

ファイル形式 tar(5) については,新たに調べてみたところ,次のような文言を見つけました. もしかしたらこれのことかもしれません.

IEEE Std 1003.1-1988 (“POSIX.1”) の初期のドラフトは、John Gilmore の pdtar プログラムや、1980 年代終わりから 1990 年代始めにかけてのシステムの実装の基礎となりました。
(中略)
IEEE Std 1003.1-1988 (“POSIX.1”) は、対応した tar(1) 実装で読み書きが出来る、標準的な tar ファイルフォーマットを定義しています。
TAR(5)


システム間での交換可能性を保ちたいのであれば,

これはまさしくその通りです.

(もはや気にする必要はありませんが) tar(1) には出力フォーマットを指定できないものもあります (SUS の tar(1) はそれの一例です). “Tarball の形式について深く考えずにアーカイブを操作したいならば pax(1) が一番かもしれないな” くらいの気分でした. もっとも,きっと最も多く使われている tar(1) は GNU tar でしょうから問題もそう多く起こらないはずです.

なるほど BSDTAR からの引用でしたか、気づきませんでした。

こちらは一つ訂正です。

シェルとユーティリティが最初に標準化された POSIX.2 (1992) に tar は含まれていません。

どうやら参照先のリストから tar の項目自体が削除されてしまっていたようです。それよりも古いリスト(こちらの Version 2 Interface Tables)を発見したので、それを調べた所 POSIX.2 に tar が含まれていたことを確認しました。

なので BSDTAR(1) の Man page …

There is no current POSIX standard for the tar command; it appeared in
ISO/IEC 9945-1:1996 ("POSIX.1") but was dropped from IEEE Std 1003.1-2001
("POSIX.1").

ISO/IEC 9945-1:1996 ("POSIX.1") は間違いで ISO/IEC 9945-2:1993 ("POSIX.2") が正しいのかもしれませんね。それはそれとして「"ISO/IEC"で登場」して「"IEEE" で削除」という書き方はおかしいわけですが。

ログインするとコメントできます