シェル変数をコマンドオプションとして使用

シェル変数をコマンドオプションとして使用

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=.nullglobfailglob

おすすめ記事