tar 実践 - 増分バックアップと除外・展開先指定

tar 実践 - 増分バックアップと除外・展開先指定

tar の増分バックアップとは?

結論: 前回からの変更分だけをアーカイブする方式。--listed-incremental でスナップショットを記録し、差分を判定する。

tar の基本で圧縮・解凍ができるようになったら、次は実務で必須の3点を押さえる。

  • 増分(差分)バックアップ: 毎回フルコピーせず、変更分だけ取る
  • 除外: node_modules やキャッシュなど不要なものを外す
  • 展開先・パス制御: どこに、どの階層で展開するかを固定する

この記事の前提

  • OS: Ubuntu(GNU tar)
  • tar --versionGNU tar と表示されること(増分・除外オプションは GNU tar 固有)
  • BSD tar(macOS 標準)では一部オプションが異なる

なぜ --listed-incremental を使うのか?

結論: --listed-incremental は削除・移動も追跡できる。--newer(mtime 比較)は削除を検知できず復元時に取りこぼす。

増分バックアップには2つの方式がある。

方式 判定基準 削除の追跡 推奨
--listed-incremental (-g) スナップショット記録 できる
--newer / --after-date mtime(更新時刻) できない

--newer は「指定時刻より新しいファイル」を拾うだけなので、前回以降に削除されたファイルを記録できない。復元すると消したはずのファイルが復活する。--listed-incremental はディレクトリ状態をスナップショットファイル(慣習的に .snar 拡張子)に記録するため、削除も含めて正しく差分を再現できる。

mtime ベースの --newer は「とりあえず差分」には使えるが、世代管理・正確な復元を要する用途では --listed-incremental を使う。

増分バックアップの作り方

結論: 同じスナップショットファイルを -g で指定し続ける。初回は自動でレベル0(フル)、2回目以降はレベル1以降(差分)になる。

レベル0(フルバックアップ)

スナップショットファイルが存在しない初回は、自動的にフルバックアップになる。

$ tar -czg /backup/home.snar -f /backup/home-full.tar.gz /home/user/
  • -g /backup/home.snar: スナップショット(--listed-incremental の短縮形)
  • -c: 作成 / -z: gzip / -f: 出力ファイル
  • 実行後、home.snar にディレクトリ状態が記録される

レベル1以降(増分)

同じスナップショットファイルを指定して再実行すると、前回からの変更分だけがアーカイブされる。

$ tar -czg /backup/home.snar -f /backup/home-inc1.tar.gz /home/user/

home.snar は実行のたびに更新され、次回の差分判定に使われる。アーカイブ名(home-inc1, home-inc2...)は世代ごとに変える。

毎回フルを取りたい場合

-g /dev/null を指定すると、スナップショットが保存されない(/dev/null は書き込んでも残らない)ため、常にレベル0フルバックアップになる。

$ tar -czg /dev/null -f /backup/full.tar.gz /home/user/

スナップショットファイルはバックアップ本体とは別に保全する。.snar を失うと差分の連鎖が切れ、次回が意図せずフル相当になったり復元手順が崩れたりする。

増分バックアップからどう復元するのか?

結論: レベル0から順に、世代順で展開する。展開時も --listed-incremental を付けると削除も再現される。

復元は作成した順番どおりに展開するのが鉄則。

$ mkdir -p /restore
$ tar -xzg /dev/null -f /backup/home-full.tar.gz -C /restore
$ tar -xzg /dev/null -f /backup/home-inc1.tar.gz -C /restore
$ tar -xzg /dev/null -f /backup/home-inc2.tar.gz -C /restore
  • 展開時の -g には /dev/null を渡す(スナップショットの中身は復元時には参照されないが、--listed-incremental モードを有効にするために指定する)
  • このモードでは、増分で削除されたファイルは展開先からも削除される(正しい世代再現)
中身を先に確認したいとき

展開前に各アーカイブの中身を一覧で確認する。

$ tar -tzf /backup/home-inc1.tar.gz | head

増分アーカイブには、変更されたファイルに加えてディレクトリのエントリも含まれる。

除外パターンの指定方法

結論: --exclude=PATTERN で個別除外、--exclude-from=FILE で一覧指定。オプションはソースパスより前に置く。

個別に除外する

$ tar --exclude='*.log' --exclude='node_modules' \
      -czf project.tar.gz project/
  • パターンは glob(* ? [...])で、アーカイブ内のメンバー名に対して照合される
  • --excludeソースパス(project/)より前に置く(後ろに置くと効かない場合がある)

除外リストをファイルにまとめる

除外対象が多いときは1行1パターンのファイルにする。

$ cat > exclude.txt <<'EOF'
*.log
*.tmp
node_modules
.cache
EOF

$ tar --exclude-from=exclude.txt -czf project.tar.gz project/

--exclude-from の短縮形は -X

よく使う専用オプション

オプション 除外対象
--exclude-vcs .git / .svn / CVS などのバージョン管理情報
--exclude-caches CACHEDIR.TAG を含むキャッシュディレクトリ
$ tar --exclude-vcs --exclude='*.log' -czf src.tar.gz src/

展開先とパス階層をどう制御するのか?

結論: -C で展開先ディレクトリを固定、--strip-components=N で先頭階層を除去、--one-top-level で1つの親に閉じ込める。

展開先を固定する(-C)

$ tar -xzf project.tar.gz -C /opt/app

カレントディレクトリに散らばる事故を防ぐ基本。展開先は事前に作っておく。

先頭の階層を除去する(--strip-components)

アーカイブが project-1.0/src/... のように1階層深い場合、その階層を剥がして展開できる。

$ tar -xzf project-1.0.tar.gz --strip-components=1 -C /opt/app

project-1.0/ を取り除き、/opt/app/src/... に直接展開される。GitHub のソース tarball を所定の場所へ展開するときの定番。

1つの親ディレクトリに閉じ込める(--one-top-level)

複数のファイルがトップレベルに散らばるアーカイブを、1つのディレクトリ配下に強制的にまとめて展開する。

$ tar -xzf messy.tar.gz --one-top-level=extracted

extracted/ が作られ、その中に展開される(散らかり防止)。

実践:日次バックアップの型

結論: 週次でレベル0、日次でレベル1を回す。除外リストと展開先固定をセットにすれば事故が減る。

コピペ用テンプレ

# 週次フル(スナップショットを初期化したい場合は .snar を消してから)
tar --exclude-from=/etc/backup/exclude.txt \
    -czg /backup/home.snar \
    -f /backup/home-$(date +%Y%m%d)-full.tar.gz \
    /home/user/

# 日次増分(同じ .snar を使い続ける)
tar --exclude-from=/etc/backup/exclude.txt \
    -czg /backup/home.snar \
    -f /backup/home-$(date +%Y%m%d)-inc.tar.gz \
    /home/user/

# 復元(フル → 増分の順、削除も再現)
tar -xzg /dev/null -f /backup/home-...-full.tar.gz -C /restore
tar -xzg /dev/null -f /backup/home-...-inc.tar.gz  -C /restore

やってはいけないこと

  • 復元を増分から先に展開する(必ずフルが先)
  • スナップショット .snar をアーカイブと同じ場所だけに置く(同時消失リスク)
  • 展開先を -C で固定せず本番ディレクトリで直接展開

定期実行は cron の基本、容量設計はディスクがいっぱいになったときも参照。

次に読む