rsyncのコピー元「A」「A/」「A/*」の違いを検証

バックアップ

こんにちは!アナサピです。
サーバーの移行やバックアップでrsyncを使うとき、コピー元の末尾に 「/」 を付けるか迷うことはありませんか?
また、 「/*」 を指定するのと他との違いがちゃんと分かっていなかったため、今回はさくらのクラウド上のサーバーで、コピー元を 「source」、「source/」、「source/*」の3通りに変え、実際にどこへ何がコピーされるか確認しました!

検証環境とファイル配置

今回は1台のサーバー内に専用の作業ディレクトリを作り、その中だけで検証しています。

比較するコマンドは次の3つです。-a はサブディレクトリを含めて属性を保持しながらコピーする指定、-v は処理内容を表示する指定です。

条件実行するコマンド
何も付けないrsync -av source backup-a/
「/」 を付けるrsync -av source/ backup-b/
「/*」 を付けるrsync -av source/* backup-c/

コピー先の3つのディレクトリは、すべて事前に作成した空の状態から始めます。コピー元には、通常のファイルと隠しファイルを置き、さらに1階層下にも両方を用意しました。

source/
├── .hidden.txt
├── test.txt
└── sub/
    ├── .nested-hidden.txt
    └── child.txt

検証用のファイルを作る

rootで専用ディレクトリを作成します。/var/tmp/lab-rsync が未使用であることを確認してから実行しました。

[root@web-01 ~]# mkdir -m 700 /var/tmp/lab-rsync
[root@web-01 ~]# cd /var/tmp/lab-rsync
[root@web-01 lab-rsync]# mkdir -p source/sub backup-a backup-b backup-c
[root@web-01 lab-rsync]# printf '%s\n' 'normal-data' > source/test.txt
[root@web-01 lab-rsync]# printf '%s\n' 'hidden-data' > source/.hidden.txt
[root@web-01 lab-rsync]# printf '%s\n' 'child-data' > source/sub/child.txt
[root@web-01 lab-rsync]# printf '%s\n' 'nested-hidden-data' > source/sub/.nested-hidden.txt
[root@web-01 lab-rsync]#

用意したのは4ファイルです。すべて検証用の文字列で、実際のバックアップデータは使っていません。

以下は採取したコマンドと出力から主要部分を掲載しています。転送量などの表示を省略した箇所は明記しています。

① 末尾に何も付けない

まずは source と指定します。

[root@web-01 lab-rsync]# rsync -av source backup-a/
sending incremental file list
source/
source/.hidden.txt
source/test.txt
source/sub/
source/sub/.nested-hidden.txt
source/sub/child.txt
~転送量などの表示を省略~
[root@web-01 lab-rsync]# ll -aR backup-a/*
backup-a/source:
total 20
drwxr-xr-x 3 root root 4096 Oct 29 20:47 .
drwxr-xr-x 3 root root 4096 Oct 29 20:47 ..
-rw-r--r-- 1 root root   12 Oct 29 20:47 .hidden.txt
drwxr-xr-x 2 root root 4096 Oct 29 20:47 sub
-rw-r--r-- 1 root root   12 Oct 29 20:47 test.txt

backup-a/source/sub:
total 16
drwxr-xr-x 2 root root 4096 Oct 29 20:47 .
drwxr-xr-x 3 root root 4096 Oct 29 20:47 ..
-rw-r--r-- 1 root root   19 Oct 29 20:47 .nested-hidden.txt
-rw-r--r-- 1 root root   11 Oct 29 20:47 child.txt
[root@web-01 lab-rsync]#

コピー先の backup-a の中に、source ディレクトリが作成されました。直下の隠しファイルも、サブディレクトリ内の隠しファイルも含め、4ファイルすべてがコピーされています。

test.txt の保存先は、backup-a/source/test.txt です。

② 末尾に「/」を付ける

次は source/ と指定します。コピー先には別の空ディレクトリを使います。

[root@web-01 lab-rsync]# rsync -av source/ backup-b/
sending incremental file list
.hidden.txt
test.txt
sub/
sub/.nested-hidden.txt
sub/child.txt
~転送量などの表示を省略~
[root@web-01 lab-rsync]# ll -a backup-b/
total 20
drwxr-xr-x 3 root root 4096 Oct 29 20:47 .
drwx------ 6 root root 4096 Oct 29 20:47 ..
-rw-r--r-- 1 root root   12 Oct 29 20:47 .hidden.txt
drwxr-xr-x 2 root root 4096 Oct 29 20:47 sub
-rw-r--r-- 1 root root   12 Oct 29 20:47 test.txt
[root@web-01 lab-rsync]# ll -a backup-b/sub/
total 16
drwxr-xr-x 2 root root 4096 Oct 29 20:47 .
drwxr-xr-x 3 root root 4096 Oct 29 20:47 ..
-rw-r--r-- 1 root root   19 Oct 29 20:47 .nested-hidden.txt
-rw-r--r-- 1 root root   11 Oct 29 20:47 child.txt
[root@web-01 lab-rsync]#

こちらでは backup-b の中に source は作られず、その中身がコピーされました。test.txt の保存先は backup-b/test.txt です。

コピーしたファイル数は①と同じ4個で、隠しファイルも含まれています。sub 以下の構造も維持されていました。

末尾の / によって変わるのは、指定した source 自体を保存先に含めるかどうかです。rsync公式マニュアル

③ 末尾に「/*」を付ける

最後に source/* と指定します。

[root@web-01 lab-rsync]# rsync -av source/* backup-c/
sending incremental file list
test.txt
sub/
sub/.nested-hidden.txt
sub/child.txt
~転送量などの表示を省略~
[root@web-01 lab-rsync]# ll -a backup-c/
total 16
drwxr-xr-x 3 root root 4096 Oct 29 20:47 .
drwx------ 6 root root 4096 Oct 29 20:47 ..
drwxr-xr-x 2 root root 4096 Oct 29 20:47 sub
-rw-r--r-- 1 root root   12 Oct 29 20:47 test.txt
[root@web-01 lab-rsync]# ll -a backup-c/sub/
total 16
drwxr-xr-x 2 root root 4096 Oct 29 20:47 .
drwxr-xr-x 3 root root 4096 Oct 29 20:47 ..
-rw-r--r-- 1 root root   19 Oct 29 20:47 .nested-hidden.txt
-rw-r--r-- 1 root root   11 Oct 29 20:47 child.txt
[root@web-01 lab-rsync]#

通常の test.txt と sub 以下はコピーされていますが、source 直下にあった 隠しファイル「.hidden.txt」 がありません。コピーされたのは3ファイルでした。
しかし、sub の中の隠しファイル「 .nested-hidden.txt」 はコピーされています。
てっきり「/*」を付ければ隠しファイルすべてが対象外になると考えておりましたが、何故こうなったのでしょうか。

なぜ「/」と「/*」で違いが出る?

今回の * をファイル名へ展開するのは、rsyncが動く前のBashです。実際にどのパスへ展開されるか、次のコマンドで確認しました。

[root@web-01 lab-rsync]# printf '%s\n' source/*
source/sub
source/test.txt
[root@web-01 lab-rsync]#

展開されたのは source/sub と source/test.txt の2つです。直下の 「.hidden.txt」 はrsyncへ渡されていません。
ただし、source/sub はコピー対象として渡されています。そこから先はrsyncが -a に含まれる再帰コピーを行うため、中の隠しファイルである、「 .nested-hidden.txt」 もコピーされていたようです。

まとめ

今回の結果は以下の通りです。

確認項目何もなし//*
コピー先に source 自体を作る作る作らない作らない
直下の test.txtコピーコピーコピー
直下の .hidden.txtコピーコピーコピーされない
sub/child.txtコピーコピーコピー
sub/.nested-hidden.txtコピーコピーコピー
コピーしたファイル数4個4個3個

今回の検証では、source と source/ は保存先の階層が変わり、source/ と source/* は直下の隠しファイルの有無が変わりました。
実際に検証してみて、/*を指定すると直下の隠しファイルはコピーされないのに、rsyncの再帰コピーによりサブディレクトリの隠しファイルはコピーされているのは言われてみれば当然なのですが、少し予想外でした。
バックアップなどでは、こういったたった一文字の違いでコピー結果に影響するため、やはりコマンドの実行結果だけでなく、実際に意図された保存がされているか確認することも大事ですね。

最後までご覧いただきありがとうございました!

この記事を書いた人

アナサピ

サービス業からのエンジニア転職。

クラウドに触れながら得た気付きや、初心者からの視点をお届け。

「これから触る人の参考になる情報」をまとめていきます!

【取得資格】

LinuC Level1

さくらのクラウド検定