scp と rsync を実測で使い分ける
同じ場所へ繰り返し送るなら rsync、1回きりなら scp です。判断の根拠は速度ではありません。送信バイト数を見ると、2回目から桁が変わります。
1.2MB のディレクトリを同じ相手へ3回送って測りました。scp は3回とも全量 (約1.2MB) を送り、rsync は2回目が 94 バイト、1ファイルだけ変えた3回目が 200,185 バイトでした。

測った条件
送るもの: 1,200,000 バイト / 2ファイル
a.bin 1,000,000 バイト
b.bin 200,000 バイト
経路: クライアント → 踏み台 → 送信先 (すべて OpenSSH 10.0p2)
3回の内訳は、1回目が相手側に何も無い状態、2回目が何も変えずにもう一度送った状態、3回目が b.bin の中身だけを作り直して送った状態です。実際の運用でいえば、初回のデプロイ、変更が無いまま流した再デプロイ、1ファイルだけ直した再デプロイに当たります。
scp は毎回おなじだけ送る
1回目 (向こうは空) : 0.246 秒
2回目 (何も変えていない) : 0.227 秒
3回目 (200KBの1つだけ変更): 0.220 秒
3回ともほぼ同じ時間です。scp は相手側に何があるかを問い合わせないので、そもそも差分という概念を持ちません。 2回目に何も変えていなくても、全量をもう一度送ります。
この計測では scp の送信バイト数を取っていなかったので、別に測り直しました。同じ大きさの2ファイルを localhost へ3回送り、scp -v の最後に出る Transferred: 行を見ると、3回とも約 1,205,000 バイトを送っていました。
1回目: Transferred: sent 1205036, received 5408 bytes
2回目: Transferred: sent 1205076, received 5344 bytes
3回目: Transferred: sent 1205128, received 5404 bytes
これは欠陥ではありません。相手の状態を問い合わせない分だけ往復が少なくて済むので、小さなファイルを1回送るだけの用途では rsync より素直に速く終わります。
rsync は差分だけを送る
1回目 (向こうは空) 転送 2ファイル / sent 1,200,471 バイト
2回目 (何も変えていない) 転送 0ファイル / sent 94 バイト
3回目 (200KBの1つだけ変更) 転送 1ファイル / sent 200,185 バイト
読み方は3つあります。
- 1回目は全量 (1,200,471 バイト) を送っていて、
scpと同じ桁です。空の相手に対しては差分が存在しないので当然です - 2回目の 94 バイトは、ファイル一覧を突き合わせただけの往復です。中身は1バイトも流れていません
- 3回目の 200,185 バイトは、変えた
b.binの 200,000 バイトとほぼ一致します。変わっていない 1,000,000 バイトのa.binは流れていません
転送後に両側で md5 を取って、中身が一致していることも確認しました。
手元 bcbba71aa361c747af5a8f03610d8a6d a.bin
向こう bcbba71aa361c747af5a8f03610d8a6d a.bin
どちらも同じ SSH 設定に乗る
rsync は自前の転送路を持たず、-e で渡した ssh をそのまま実行します。つまり ~/.ssh/config に書いた設定がそのまま効きます。
rsync -a -e ssh site/ target:~/site/
踏み台越しでも、ssh 側が通っていれば追加の設定は要りませんでした。転送の設定を別に持つ必要はありません。 設定の一本化は次の章で扱います。
scp が非推奨という話の正体
scp について「非推奨」と言われるのは、コマンドではなく中で使っていたプロトコルのほうです。
OpenSSH 9.0 の変更点にこうあります。
This release switches scp(1) from using the legacy scp/rcp protocol to using the SFTP protocol by default.
旧来の scp/rcp プロトコルは、送ったファイル名をリモート側のシェルが解釈する設計だったため、空白や記号を含む名前を送るときには二重引用符で囲んでシェルに食わせない作法が要りました。SFTP に切り替わったことで、その作法は不要になっています。

ただし、プロトコルが変わっても変わらない挙動があります。scp -r site 相手:site を2回打つと、2回目は site/site の入れ子になります。OpenSSH 10.0p2 のコンテナから localhost に向けて試すと、既定の SFTP でも、旧プロトコルを強制する -O でも同じように入れ子になりました。
$ scp -r site localhost:site # 1回目
$ scp -r site localhost:site # 2回目
$ find site -type f | sort
site/a.bin
site/b.bin
site/site/a.bin
site/site/b.bin
送り先のディレクトリが既にあれば、その中にコピーする。cp -r と同じ決まりで、プロトコルとは関係がありません。同じ場所へ繰り返し送るなら、中身だけを送る rsync -a site/ 相手:site/ のほうが入れ子の事故が起きません。 送り元の末尾のスラッシュは「中身だけ」という意味です。

この章の結論
1回きりなら scp、繰り返すなら rsync。境目は回数です。2回目からは送信バイト数が桁で変わるので、同じ場所へ1日に何度も送る使い方をしているなら、そこだけでも rsync に替える価値があります。どちらも ~/.ssh/config に乗るので、経路の設定は1箇所で済みます。その1箇所を次の章で作ります。
この記事は役に立ちましたか?