rsync

rsync --delete で泣かないために

More than 3 years have passed since last update.

はじめに

ファイルを別のディレクトリにバックアップする際は rsync コマンドが便利ですよね!
そして --delete オプションも活用すると、コピー元で削除されたファイルをコピー先でも削除してくれるので
ディレクトリの内容を同期するのに便利です。
ミラーリング用のアプリなんてもう要らねえ!
ただし、不用意に rsync --delete を利用すると……死にます!

僕も今日、複数の外付けハードディスクのデータを整理するのに
(僕自身は普段あまり使わない) rsync コマンドを --delete オプションとともに利用していました。

その時、事件は起こりました。
不用意にこのコマンドを実行してしまったがために、コピー先のディレクトリに存在した削除したくない、大切なファイル群まで消してしまったのです!

というわけで、僕と同じような rsync 初心者の方が同じような悲劇を生まないためにも
この記事を残します。

具体例

例えば、以下の様なディレクトリ構成を想定します。
src がコピー元、dst がコピー先のディレクトリです。

home/
  ├ src/
  │  └ magica/
  │        ├ devil/
  │        │    └ homura.txt
  │        ├ kyoko.txt
  │        ├ madoka.txt
  │        └ sayaka.txt
  └ dst/
     └ mami.txt

これを rsync を利用して以下のような構成にしたいです。

home/
  ├ src/
  │  └ magica/
  │        ├ devil/
  │        │    └ homura.txt
  │        ├ kyoko.txt
  │        ├ madoka.txt
  │        └ sayaka.txt
  └ dst/
     ├ magica/
     │      ├ devil/
     │      │    └ homura.txt
     │      ├ kyoko.txt
     │      ├ madoka.txt
     │      └ sayaka.txt
     └ mami.txt

今回のポイントは以下の2つです。

  1. src/magica ディレクトリを dst ディレクトリ以下にコピーしたい。
  2. dst/mami.txt は大切なファイルなので削除しちゃだめ!

この場合に、以下のどちらのコマンドを実行するかで運命が大きく変わります。

$ rsync -av --delete src/magica dst
$ rsync -av --delete src/magica/ dst

今回の場合は上が正解のコマンドです。
下のコマンドを実行すると、以下のようなディレクトリ構成になってしまいます。

home/
  ├ src/
  │  └ magica/
  │        ├ devil/
  │        │    └ homura.txt
  │        ├ kyoko.txt
  │        ├ madoka.txt
  │        └ sayaka.txt
  └ dst/
     ├ devil/
     │    └ homura.txt
     ├ kyoko.txt
     ├ madoka.txt
     └ sayaka.txt

マミった!!!

なぜマミさんは死んだのか

rsync コマンドで重要なのが、コピー元の最後が / (スラッシュ) で終わるか終わらないかで挙動が異なる ということです。
/ で終わる場合、コピー元のディレクトリ自体はコピーせずに、ディレクトリ内のファイルをすべてコピーするという挙動になります。
こんなイメージですかね。

$ rsync -av --delete src/magica/* dst

そのため、magika ディレクトリはコピーされず、その中にあったファイルが dst ディレクトリ以下にコピーされたのです。
ここで悲劇的なのが --delete オプションを指定したために、コピー元の magika ディレクトリ以下にないと判断された mami.txt が削除されたことです。

/ さえ無ければ magika ディレクトリごとコピーされ、このような悲劇は起きなかったのに…。

その他の対策として

そもそも --delete というファイルの削除を伴う危険なオプションを利用しているのにもかかわらず、
不用心にもそのまま実行したのが間違いでした。
こういう場合は dry-run (お試し実行) すべきです。
もちろん rsync にも dry-run 用のオプションが存在します。-n オプションです。

$ rsync -avn --delete src/magica/ dst
building file list ... done
deleting mami.txt
./
kyoko.txt
madoka.txt
sayaka.txt
devil/
devil/homura.txt

sent 213 bytes  received 56 bytes  538.00 bytes/sec
total size is 0  speedup is 0.00

deleting mami.txt だって!? 危ない危ない…。

$ rsync -avn --delete src/magica dst
building file list ... done
magica/
magica/kyoko.txt
magica/madoka.txt
magica/sayaka.txt
magica/devil/
magica/devil/homura.txt

sent 224 bytes  received 56 bytes  560.00 bytes/sec
total size is 0  speedup is 0.00

⊂(^ω^)⊃ セフセフ

これで心置きなく rsync --delete を実行できますね。

$ rsync -av --delete src/magica dst

参考