Bashスクリプトは、使用するオプションを別の変数に保存しようとしますrsync
。これは単純なオプション(例:)ではうまく機能します--recursive
が、次の問題が発生します--exclude='.*'
。
$ find source
source
source/.bar
source/foo
$ rsync -rnv --exclude='.*' source/ dest
sending incremental file list
foo
sent 57 bytes received 19 bytes 152.00 bytes/sec
total size is 0 speedup is 0.00 (DRY RUN)
$ RSYNC_OPTIONS="-rnv --exclude='.*'"
$ rsync $RSYNC_OPTIONS source/ dest
sending incremental file list
.bar
foo
sent 78 bytes received 22 bytes 200.00 bytes/sec
total size is 0 speedup is 0.00 (DRY RUN)
ご覧のとおり、「手動」--exclude='.*'
で渡すとうまく機能しますが(コピーなし)、オプションが最初に変数に保存されたときは機能しません。rsync
.bar
私はこれが引用符やワイルドカード(またはその両方)に関連していると思いますが、何が間違っているのかわかりません。
ベストアンサー1
一般に、コマンドラインオプションのリストでもパス名のリストでも、個々のエントリのリストを単一の文字列に減らすことはお勧めできません。その理由は、行の下のどこかで文字列を別の内容に再分割する必要があり、文字列に意味論的解釈が容易な場合や重要ではない可能性がある引用符とスペースが含まれていると正しく実行できないためです。文字列のデータです。
代わりに配列を使用してください。
rsync_options=( -rnv --exclude='.*' )
または
rsync_options=( -r -n -v --exclude='.*' )
それから...
rsync "${rsync_options[@]}" source/ target
これにより、個々のオプションへの参照を維持できます(拡張を二重引用符で囲む限り${rsync_options[@]}
)。また、配列内の個々の項目を簡単に操作できます(呼び出し前にそうする必要がある場合)rsync
。
すべてのPOSIXシェルで位置引数リストを使用してこれを達成できます。
set -- -rnv --exclude='.*'
rsync "$@" source/ target
ここでも二重引用符の拡張が$@
重要です。
接線的に関連する:
問題は、両方のオプションセットを文字列に入れると、--exclude
オプション値の一重引用符が値の一部になることです。したがって、
RSYNC_OPTIONS='-rnv --exclude=.*'
効果がありましたが...別の参照項目を持つ配列または位置パラメータを使用する方が安全です。これにより、必要に応じてスペースを含むコンテンツを使用でき、シェルがオプションに対してファイル名を生成するのを防ぎます。
¹ 次の名前で始まるファイルが変更さ$IFS
れておらず、現在のディレクトリに存在しないか、シェルオプションが設定されていない場合。--exclude=.
nullglob
failglob