[Shell] rsyncはスラッシュ/の有無で何が変わるのか?
rsyncは、ディレクトリを同期するのによく使います。しかし、ファイルパスの書き方でときどき混乱します。
混乱するのは、パス末尾のスラッシュの有無で挙動が変わるからです。
というわけで、同期するときのパスの書き方を整理してみました。
まずは理屈はさておき、ディレクトリを同期する構文としては、次の構文を暗記しておけば、いいでしょう(オプション-av
は基本的な設定ですので、もう少し必要ですがここでは触れません)。
rsync -av SRC/PATH/ DEST/PATH/
で、この構文は、このように理解しておけばいいのです。
rsync -av ${どのファイル/ディレクトリを} ${どこへ置くか}
今まで混乱したのは、次のように考えていたからですが、これが間違いのもとでした。
NG: rsync -av ${同期したいディレクトリA} ${同期したいディレクトリB}
正しくは、次の2パターンで考えます。
OK: rsync -av ${同期したいディレクトリAの中身} ${どこへ置くか}
OK: rsync -av ${同期したいディレクトリA} ${どこへ置くか}
送信元の書き方に、2パターンあるわけです。それぞれを構文的に書けば、次のようになります。
rsync -av /SRC/A/ /DEST/B/
rsync -av /SRC/A /DEST/
微妙の差なので、わかりにくいですが、スラッシュの有無に注意してください。
それではそれぞれのパターンについて説明します。
スラッシュあり:rsync -av /SRC/A/ /DEST/B/
まずはスラッシュが末尾にある/SRC/A/
のパターンです。/SRC/A/
はディレクトリAの中身を表わします。
したがって、この例では、”ディレクトリAの中身をどこへ置くか?”と考えて、受信先のパスを選びます。
今回の例では、ディレクトリBのなかへ置きたいわけですから、/DEST/B/
と指定しています。
ちなみに、受信先の/DEST/B/
は、スラッシュを省略して/DEST/B
と書いても同じです。今回はディレクトリであることを明示したいのでつけています。
この構文では、ディレクトリの中身を操作しているイメージです。
スラッシュなし:rsync -av /SRC/A /DEST/
一方、スラッシュなしで/SRC/A
と指定した場合、ディレクトリA本体を表わします。
したがって、この場合は、”ディレクトリAをどこへ置くのか?”と考えて、受信先のパスを選べばいいわけです。
ここでディレクトリAを置きたいのは/DEST/
です。だからそのように指定しています。
このように、この構文はディレクトリ本体を操作しているイメージです。
まとめ
以上、2パターンの結果は同じなのですが、送信元のスラッシュ有無という小さな違いが、操作する対象とパスの書き方に違いがあります。
- 送信元の末尾
/
有無の違い - 受信先の末尾
/
有無はどちらもでいい
最後に、ありがちな間違った例をあげておきます。
$ rsync -av /SRC/A /DEST/B
# NG: "ディレクトリA本体"がディレクトリBのなかにコピーされます
$ rsync -av /SRC/A/ /DEST/
# NG: "ディレクトリAの中身"が親ディレクトリにコピーされます
以上、参考になりましたら幸いです。
(追記)
あとで気付いたのですが、そもそもcp
コマンドも同じような仕様っぽいのですね。cp /dir/sub /other/
みたいな使い方しかしなかったので、気付いてませんでした(汗)。