こんにちは!アナサピです。
サーバーの移行やバックアップで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の再帰コピーによりサブディレクトリの隠しファイルはコピーされているのは言われてみれば当然なのですが、少し予想外でした。
バックアップなどでは、こういったたった一文字の違いでコピー結果に影響するため、やはりコマンドの実行結果だけでなく、実際に意図された保存がされているか確認することも大事ですね。
最後までご覧いただきありがとうございました!