サーバーのファイルを手元へ持ってくるとき、私はずっと cp と scp だけで済ませていました。
ところが同じディレクトリを何度も往復させるようになると、毎回まるごと転送する待ち時間がばかになりません。
そこで rsync に乗り換えたところ、2回目以降の実行が体感で一瞬になりました。
rsync は「前回との差分だけを送る」ことに特化したコピーコマンドです。
この記事では、私が普段実際に打っている範囲のオプションだけを、実行結果つきで並べていきます。
検証環境は Ubuntu 22.04.5・rsync 3.2.7(protocol 31)でした。
まずは -av だけ覚える
基本形は rsync に続けてオプション、コピー元、コピー先を並べるだけ。
最初に覚えるオプションは -a と -v の2つで足ります。
-a は archive の頭文字で、サブディレクトリ・パーミッション・タイムスタンプをまとめて保ったまま運ぶ指定。
-v は verbose、つまり何を転送したかを画面に出す指定です。
$ rsync -av src/ dst/
sending incremental file list
a.txt
b.log
sub/
sub/c.txt
sent 352 bytes received 85 bytes 874.00 bytes/sec
total size is 20 speedup is 0.05
4つのエントリが転送され、サブディレクトリもそのまま再現されました。
おもしろいのは、続けてもう一度まったく同じコマンドを打ったとき。
$ rsync -av src/ dst/
sending incremental file list
sent 188 bytes received 13 bytes 402.00 bytes/sec
total size is 20 speedup is 0.10
ファイル名が1つも並びません。
中身が変わっていないファイルは、まるごと読み飛ばされているわけです。
では a.txt だけ書き換えてから、三度目を実行してみます。
$ printf 'alpha-updated\n' > src/a.txt
$ rsync -av src/ dst/
sending incremental file list
a.txt
sent 249 bytes received 36 bytes 570.00 bytes/sec
total size is 28 speedup is 0.10
変わった1ファイルだけが選ばれて流れました。
この挙動こそが、cp との決定的な違いになります。
いちばんの事故は、末尾スラッシュ
rsync で最初につまずくのは、オプションではなくコピー元の末尾スラッシュでした。
同じ src を指しているつもりでも、スラッシュの有無で結果が変わります。
$ rsync -a src/ d1/ # src の「中身」を d1 直下へ
$ rsync -a src d2/ # src「ごと」d2 の下へ
$ find d1 | sort
d1
d1/a.txt
d1/b.log
d1/sub
d1/sub/c.txt
$ find d2 | sort
d2
d2/src
d2/src/a.txt
d2/src/b.log
d2/src/sub
d2/src/sub/c.txt
d2 のほうだけ、src という階層が1段よけいに増えました。
スラッシュを1つ落としただけで、コピー先の構造が変わってしまう。
迷ったときは -n、つまり –dry-run を足して、転送されるはずのファイル名だけ先に眺めます。
$ printf 'delta\n' > src/d.txt
$ rsync -avn src/ dst/
sending incremental file list
./
d.txt
sent 224 bytes received 23 bytes 494.00 bytes/sec
total size is 34 speedup is 0.14 (DRY RUN)
末尾に (DRY RUN) と出ているとおり、この実行ではコピー先に1バイトも書かれていません。
私は初見のディレクトリを相手にするとき、必ずこの -n 付きを一度はさむようにしています。
–delete と –exclude は意味を掴んでから
コピー先をコピー元の鏡写しにしたいなら –delete の出番です。
$ rm src/b.log
$ rsync -av --delete src/ dst/
sending incremental file list
deleting b.log
./
d.txt
sent 254 bytes received 55 bytes 618.00 bytes/sec
total size is 28 speedup is 0.09
コピー元から消したファイルが、コピー先でも削除されました。
–delete は取り消しのきかない削除を伴うので、–dry-run で確認してから本番に回す。
逆に、そもそも送りたくないものは –exclude で外しておきます。
$ rsync -av --exclude='*.log' src/ dst2/
sending incremental file list
created directory dst2
./
a.txt
d.txt
sub/
sub/c.txt
拡張子 .log のファイルだけが候補から外れました。
ログやキャッシュを巻き込まずに済むので、実務ではこちらのほうが出番が多い印象。
リモートを相手にするときの形
コピー元かコピー先のどちらかを user@host:/path と書けば、そのまま ssh 越しの転送になります。
ローカル同士との違いは、この1点だけ。
鍵の作り方や ~/.ssh/config での短縮は、SSH 側の記事にまとめています。
# リモートのログ置き場を手元へ取り寄せる
rsync -avz --progress user@example.com:/var/log/myapp/ ./logs/
# 途中で切れても、同じコマンドを打ち直せば続きから
rsync -avzP user@example.com:/var/log/myapp/ ./logs/
-z は転送時の圧縮、–progress は進捗表示の指定です。
-P はその –progress と –partial をまとめたもので、途中まで届いたファイルを捨てずに残す働きをします。
だから回線が切れても、同じコマンドをもう一度叩けば残りだけが流れる。
なお上のリモート例は書式を示したもので、手元の検証はローカル同士のディレクトリで行いました。
最後に
rsync は cp の置き換えというより、2回目以降が劇的に速くなるコピーだと捉えると腑に落ちます。
覚える順番は -av、次に –dry-run、最後に –delete と –exclude の3段でじゅうぶんでした。
末尾スラッシュだけは、今でも打つ手を一度止めて確かめるのが習慣です。
まるごと固めて持ち出したいときは、差分コピーではなく tar の出番。
詳しい仕様はrsync 公式サイトと man rsync が一次情報になります。
以上です。










コメントを残す