🔰

イマドキなtarコマンドの基本と、SSHを介した便利な使い方

2024/05/20に公開

tarは便利なコマンドではあるものの、慣れていない人にとっては扱いづらく、いくつか注意点もあるコマンドです。

またリモートにあるサーバとファイルのやり取りをする際、 scp などを使うことが多いと思います。
これもファイル数の多いディレクトリやサイズの大きいテキストファイルを扱う際は、tarを使うことで効率的に行える場合もあります。

そのためtarコマンドの注意点やリモートサーバとのやり取りで覚えておくとよい使い方を記載します。

tarコマンドの注意点

(使い方だけ知りたい方は、基本的な使い方 までスキップしてください)

tar は Tape ARchive という名称から来ていることからもわかる通り、とても歴史が古いコマンドです。
それ故に普通のUnix系コマンドとは異なる点、注意点があります。

オプションのハイフン( - )

オプションの指定にハイフン - は必須ではありません。

ただし後述する -C オプションなどの後に使う場合は必須となるため、原則ハイフンは省略しないことをオススメします。

具体的な例

以下2つのコマンドは同じ動きをします。

# ハイフンを使わない(昔ながらの指定方法)
tar czvf /home/user/hoge.tar.gz archive_directory

# ハイフンを使う(一般的なUnixコマンドと同じ方法)
tar -czvf /home/user/hoge.tar.gz archive_directory

しかしながら他のオプションが先に来ている場合、ハイフンは省略できません。
ややこしいので他のUnixコマンドと同じように、オプションには常にハイフンをつけることをおすすめします。

# これは想定通り動く
tar -C /path/to/dir -czvf /home/user/hoge.tar.gz archive_directory

# これは想定通りには動かない!!
tar -C /path/to/dir czvf /home/user/hoge.tar.gz archive_directory

アーカイブ・圧縮対象のパスに絶対パスは指定しない

以下のように tar でアーカイブ・圧縮する対象のフォルダを絶対パスで指定したとします。

tar -czvf ./hoge.tar.gz /absolute/path/archive_directory
#                       ^ ここが絶対パスになっている

この場合、ほとんどの方にとって意図しない動作となる可能性が高いため、絶対パスは使わないでください。
具体的なパスの指定方法は、基本的な使い方 で説明します。

詳しい説明

アーカイブ先に絶対パスを指定した場合、展開・解凍時の挙動は以下のどちらかになります。

  • /absolute/path/archive_directory 配下にファイルが作られる(絶対パスで展開される)
  • 展開・解凍コマンドを実行したカレントディレクトリ配下に、absolute/path/archive_directory/ が作られて、その配下にファイルが展開される
    • ホームディレクトリでコマンド実行したとすると、最終的に ~/absolute/path/archive_directory/ というディレクトリ構成が誕生します

前者の挙動の場合、既存のディレクトリを破壊しかねないのでかなり危険な動作です。
おそらくよほど古いOSでない限りは、後者の挙動になるかと思います。[1]

ただ、いずれにしても望ましい挙動ではないと思うので、アーカイブ元のパス指定で絶対パスはNGです。
(保存先の指定で絶対パスを使う分には全く問題ありません)

この問題への回避法は、2つあります。

  1. アーカイブしたいフォルダの親ディレクトリまで移動して、相対パスでディレクトリを指定する
  2. -C オプションを使用する

基本的には -C オプションを使用するのが汎用性が高くおすすめです。
基本的な使い方」の章で具体的な使用法を説明します。

アーカイブ・圧縮対象のパスの末尾にスラッシュを含めない

以下のように対象パスの末尾にスラッシュを含めると、archive_directory ディレクトリ自体は含まずにその配下のファイルのみがアーカイブ・圧縮されます。

tar -czvf ./hoge.tar.gz archive_directory/

この場合にどうなるかというと、展開・解凍を実行したフォルダの配下に archive_directory 配下のファイルが撒き散らされることになります。

これが意図した挙動であることはあまり無いと思われるので、対象フォルダの末尾にはスラッシュを付けないことをおすすめします。

詳しい説明

archive_directory の構造が以下だったとします。

archive_directory
├── file1.txt
└── subdir
    └── file2.txt
  1. スラッシュを含まないパスを指定した場合

    tar -czvf ./hoge.tar.gz archive_directory
    

    この場合、展開したカレントディレクトリに archive_directory ディレクトリが作成され、ファイルやサブディレクトリもその配下に配置されます。
    アーカイブ時の構造をそのまま維持するので、多くの場合で違和感はないでしょう。

    # ホームディレクトリで展開したとする
    /home/user
    └── archive_directory
        ├── file1.txt
        └── subdir
            └── file2.txt
    
  2. スラッシュを含むパスを指定した場合

    tar -czvf ./hoge.tar.gz archive_directory/
    

    この場合、展開したディレクトリに archive_directory は作られず、archive_directory 配下のファイルとサブディレクトリが直接配置されます。

    例では2つしかファイルがないのでそこまで気にならないかもしれませんが、1000個のファイルをデスクトップ直下に展開してしまう、などと考えれば恐ろしさが伝わると思います。

    # ホームディレクトリで展開したとする
    /home/user
    ├── file1.txt
    └── subdir
        └── file2.txt
    
展開時にディレクトリを作らない方法

もしスラッシュを付けずにアーカイブした上で、展開時に archive_directory を作らず直下にファイルを配置したい場合、オプションを指定することで実現可能です。

tar -xvf hoge.tar.gz --strip-components 1

基本的な使い方

以下では最も使われているgzip圧縮を行うとして、オプション指定を行います。

gzip以外の圧縮アルゴリズムを指定する場合は オプションの補足 を参照してください。

アーカイブと圧縮、展開と解凍の違い

アーカイブとは、複数のファイルやディレクトリを1つのファイルにまとめることです。単にまとめているだけで、データ容量を減らすことは行いません。
圧縮はよく使われますし、言葉通りの意味なのでイメージしやすいかと思います。これはデータを効率化し容量を削減します。

展開とはアーカイブの逆操作、解凍は圧縮の逆操作になります。

tar コマンドは本来、複数のファイルやディレクトリを1つにまとめるアーカイブとしての機能しかありませんでした。
その後拡張が行われ、オプションを指定することでgzipなどの形式で圧縮ができるようになりました。
拡張子が .tar.gz などとなっているのは、tarでアーカイブしたファイルに対して、gzipで圧縮を行っているためです。

Windowsでよく使われるZipでは、フォルダを圧縮することができますが、これはZipがアーカイブと圧縮を同時に扱えるフォーマットのためです。
Zipでは当たり前のようにフォルダを圧縮できますが、gzipのように圧縮のみでアーカイブができない(単一のファイルしか圧縮できない)圧縮プログラムのほうが多いです。

アーカイブ・圧縮

z オプションでgzip圧縮まで行います。
以下ではgzip圧縮を行う前提ですが、z オプションを指定しなければ、アーカイブのみ行います。

カレントディレクトリ直下のディレクトリを圧縮する

# gzip圧縮を行う
tar -czvf /save/path/hoge.tar.gz dir_name

# アーカイブのみ
tar -cvf /save/path/hoge.tar dir_name

# bzip2 (.tar.bz2) で圧縮する
tar -cjvf /save/path/hoge.tar.bz2 dir_name

# xz (.tar.xz) で圧縮する
tar -cJvf /save/path/hoge.tar.xz dir_name

-C オプションを使い、直下以外のディレクトリを圧縮する

tar -C /path/to -czvf /save/path/hoge.tar.gz dir_name
-C オプションの順序

下記でも同じ動作になりますが、-C オプションでのパスと、アーカイブするディレクトリ名の間の半角スペースの入れ間違いを防止するため、-C オプションを前に書くことをおすすめします

tar -czvf /save/path/hoge.tar.gz -C /path/to dir_name

# tab補完で無意識にこうしてしまうのを防止
tar -czvf /save/path/hoge.tar.gz -C /path/to/dir_name
#                                           ^ / で補完してしまっている

展開・解凍

展開と解凍の場合では、特にオプションを区別する必要はありません。
対象ファイルの先頭数バイトを見てフォーマットを判別してくれるためです。

カレントディレクトリに展開する

tar -xvf /path/hoge.tar.gz

展開先ディレクトリを指定する

tar -C /path/to -xvf /path/hoge.tar.gz

tarファイルの中身を確認

tar -tf /path/to/hoge.tar.gz

展開時にディレクトリを作らない方法

これまで説明してきたように、基本的にtarでの圧縮対象はディレクトリそのもの(末尾スラッシュを付けない)とするため、展開時には圧縮したディレクトリが作成されることになります。

これをせず直下にファイルを配置したい場合、オプションを指定することで実現可能です。

tar -xvf hoge.tar.gz --strip-components 1

--strip-components オプションでは、展開後のディレクトリを指定した階層分だけ切り捨てることができます。
ここでは1階層を切り捨てることで、直下にファイルを展開させています。

オプションの補足

  • -c オプションは create の略で、-x オプションは extract の略です
  • -czvf や -xvf の -v オプションは処理中の内容を詳しく出力するフラグ(ほかのUnix系コマンドによくあるもの)で、-f オプションはアーカイブファイルのパスを指定するもの
  • -f オプションは f の後ろに来るものをファイルとして取るため、直後に別のオプションを記述しないこと
    • -cfzv などの順序にすると、z をアーカイブファイル名として解釈されてしまう
  • 圧縮時の形式は、 z オプションでgzip (.tar.gz)、j オプションでbzip2 (.tar.bz2)、J オプションでxz (.tar.xz)の圧縮を行う
    • a オプションを使うとアーカイブファイル名を見て圧縮形式を自動判別してくれます
    • 解凍時はファイルの先頭数バイトを見て自動判別してくれるため、圧縮形式の指定は不要です

SSH経由での転送

以下で /path/local はローカルPC側のパス、/path/remote リモートサーバ側のパスとします。

単体のハイフン - は標準入出力を表しています。
アーカイブデータを標準入出力して、それをSSH経由で転送するような動きをさせています。

リモートで圧縮してローカルに転送、ローカルに圧縮ファイルとして保存

ssh [user]@[host] "tar -C /path/remote -czvf - hoge" > /path/local/fuga.tar.gz

リモートでアーカイブし、ローカルへ転送後に展開

ssh [user]@[host] "tar -C /path/remote -cvf - hoge" | tar -xf -

# リモートでgzip圧縮まで行う
ssh [user]@[host] "tar -C /path/remote -czvf - hoge" | tar -xf -

カレントディレクトリ以外で展開する場合

ssh [user]@[host] "tar -C /path/remote -cvf - hoge" | tar -C /path/local -xf -

ローカルのファイルを圧縮して転送、リモートで解凍

tar -C /path/local -czvf - hoge | ssh [user]@[host] "tar -C /path/remote -xf -"

リモート側で解凍せずに圧縮ファイルで保存する場合

tar -C /path/local -czvf - hoge | ssh [user]@[host] "cat > /path/remote/hoge.tar.gz"

まとめ

以上 tar コマンドの使い方と注意点でした。

特に大量のファイルがあるディレクトリの転送などは、一度tarにまとめることでパフォーマンスが向上することもあります。紹介したコマンドでの転送も試してみてください。

補足として、テキストファイルが多い場合などであれば圧縮は効果がありますが、すでに圧縮されているjpg画像などが多い場合、tarファイルを圧縮してもそこまで効果がない場合があります。

この場合は、圧縮処理にかかる時間を考えると、圧縮はせずにtarballで送ったほうが時間効率が高いこともあります。
状況に応じて使い分けることをおすすめします。

脚注
  1. アーカイブ時に -P オプションを指定すると、前者の「絶対パスで展開するようにアーカイブ」とすることができます。 ↩︎

GitHubで編集を提案

Discussion