その前に include と exclude オプションとは
rsync コマンドには --include オプションと --exclude オプションがある。それぞれの意味は以下の通り。- --include : --include="hogehoge" で指定した文字列にマッチするファイルまたはディレクトリが同期対象となる
- --exclude : --exclude="hogehoge" で指定した文字列にマッチするファイルまたはディレクトリが同期対象から除外される
つまり /var の中の httpd.log のみを同期することや /var の中の httpd.log 以外を同期するといったことが可能となる。
じゃあやってみよう
ということで以下のようなディレクトリとファイルがあるとする。
同期対象のディレクトリ構成
これに対して以下のコマンドを実行する。
rsync -av --delete --include="config" rsync_test/ to_dir01予想では rsync_test/config のみが to_dir01 に作成されるはずだ。だが、実際は…
となり、すべて同期されてしまう。
ここで、 man などでヘルプを見てみて--excludeと一緒に指定しないと駄目そうと判明したので以下のように実行してみた。デフォルト全て除外でconfigだけ対象という意図だ。
rsync -av --delete --exclude="*" --include="config" rsync_test/ to_dir02これで実行した結果が以下のようになる。
きちんと指定しているにも関わらずすべて対象外となり何も同期されない。この時、
- 指定方法がフルパスじゃないと駄目?
- 対象がディレクトリだから最後に / がないと駄目?
という試行錯誤を小一時間繰り返したが解決しない…。
include と exclude オプションは順序が大事
man を見ても分からないのでGoogle先生に聞いてみた。そしたら以下のサイトが見つかった。
まさに今回の件にドンピシャ。ということで以下のように変更してみた。
rsync -av --delete --include="config" --exclude="*" rsync_test/ to_dir03これで実行した結果がこちら。
うまくいった。結局は使い方が間違っていたということか。
にしても今までコマンドをいろいろ使ってきたけどコマンドラインオプションに順序性があることがあるということを初めて知った。なんとなく違和感があるけどそういうものなのか…
include と exclude の指定方法による実行結果への影響
ということでうまくいったのでいろんなパターンを試してみる。
1.includeで直下のファイル名を指定した場合
rsync -av --delete --include="Rakefile" --exclude="*" rsync_test/ p01
対象のファイルのみが同期され、それ以外のファイルディレクトリ、ファイルは除外された。
2.includeで直下のディレクトリ名を指定した場合
rsync -av --delete --include="app" --exclude="*" rsync_test/ p02
対象のディレクトリのみが同期され、そのディレクトリ内のファイル、ディレクトリ、およびそれ以外のファイル、ディレクトリは除外された。
3.includeで直下でないディレクトリ名を指定した場合(失敗)
rsync -av --delete --include="controllers" --exclude="*" rsync_test/ p03
controllersという名前のディレクトリは存在していますが、パスの指定方法は相対パス指定であるため、今回の指定方法の場合はrsync_test/controllersというディレクトリを指定していることになり、そのようなディレクトリはないため何も同期されないという結果になる。
4.includeで直下でないディレクトリ名を正しく指定した場合(失敗)
rsync -av --delete --include="app/controllers" --exclude="*" rsync_test/ p04
今回は正しく指定しているにも関わらず、対象のディレクトリが作成されていない。つまり、この指定方法ではうまくいかない。原因は後回しにし次のパターンへ。
5.includeで直下でないディレクトリ名と対象ディレクトリの親ディレクトリを同時に指定した場合
rsync -av --delete --include="app" --include="app/controllers" --exclude="*" rsync_test/ p05
今回はうまくいった。つまりサブディレクトリを指定したい場合は、対象のディレクトリに至るまでの全ての親ディレクトリを--includeで指定する必要があるということだ。
6.includeでディレクトリ名/*を指定した場合(失敗ケース)
rsync -av --delete --include="app" --include="app/controllers/*" --exclude="*" rsync_test/ p06
appまでは作成されたがapp/controllers以降が作成されなかった。これはapp/controllers/*はあくまで指定したディレクトリに存在するファイルやサブディレクトリを対象としているのであり、その時点でapp/controllersディレクトリが対象に含まれていないためにapp/controllersディレクトリが作成されないためファイルやサブディレクトリが作成されない。つまり、は次のように指定する必要がある。
7.includeでディレクトリ名/*を指定した場合
rsync -av --delete --include="app" --include="app/controllers" --include="app/controllers/*" --exclude="*" rsync_test/ p07
このように実行すれば目的の動作となる。これはなんとかならないものか…。
8.includeでディレクトリ名/**を指定した場合
rsync -av --delete --include="app" --include="app/controllers" --include="app/controllers/**" --exclude="*" rsync_test/ p08
指定したディレクトリに含まれるファイルとサブディレクトリ、そのサブディレクトリに含まれるファイルやサブディレクトリ全てが同期される。
まとめ
includeについてはひとまずこれで終了。まとめると以下のようになる。
- include で特定のディレクトリやファイルを指定したい場合は include を先に書いて --exclude="*" を後に指定しなければならない
- include でファイルやディレクトリを指定する場合は相対パスで指定しなければならない
パターン3を参照 - include でサブディレクトリやサブディレクトリにあるファイルを指定する場合は、対象のファイルまたはディレクトリに至るまでのディレクトリをすべて--includeで指定しなければならない
パターン5を参照 - include でディレクトリ以下のファイルを指定したい場合は対象のディレクトリと対象のディレクトリ内のファイル(ディレクトリ)は別々に --include で指定しなければならない
→ パターン7,8 を参照
余談
excludeはまとめる予定は今のところなし…。
分かりやすかった。助かりました。
返信削除バージョン2.6.7以降だと--include="app/***" --exclude="*"で対象に至るまでのディレクトリをすべて--includeで指定しなくても済みますよ。
返信削除当時使用していたバージョンが何かは既に環境がないのでわかりませんが、
返信削除最近だとその方法が使えるのですね。
有用な情報ありがとうございます。