Bashシェルでバックアップスクリプトのコマンドラインを生成しようとしています。
簡単な例:
EXCLUDES="/home/*/.cache/* /var/cache/* /var/tmp/* /var/lib/lxcfs/cgroup/*";
for FOLDER in $EXCLUDES; do printf -- '--exclude %b\n' "$FOLDER" ; done
結果は次のとおりです。
--exclude '/home/*/.cache/*' --exclude '/var/cache/*' --exclude '/var/tmp/*' --exclude '/var/lib/lxcfs/cgroup/*'
しかし、問題は、これらのフォルダがシェルから拡張されることです。 echo/printf/quoting/IFSを使って多くの例を試しましたが、正しい結果はありません。
この問題に対する解決策はありますか?
答え1
パス名のリスト、ファイル名グローバル変数を含むパス名のリスト、または繰り返しまたは一部のコマンドの引数リストとして使用する一般的なリストを指定する必要がある場合は、必ず配列を使用してください。
配列以外の文字列を使用している場合は、空白のある項目を処理できません(文字列でスペースを区切り文字として使用しているため)。また、トークン化(変数を引用せずに拡張)を呼び出す必要があるため、文字列の内容を繰り返すことも困難です。しかし、これが原因ですset -f
。
ほとんどのシェルでは、通常のシェルでも/bin/sh
配列を使用できます。では、sh
位置引数配列($@
)を使用します。
のbash
場合は、引用符付きの文字列配列を使用してください。
excludes=( '/home/*/.cache/*'
'/var/cache/*'
'/var/tmp/*'
'/var/lib/lxcfs/cgroup/*' )
次に、
rsync_opts=( --verbose --archive )
for excl in "${excludes[@]}"; do
rsync_opts+=( --exclude="$excl" )
done
後、
rsync "${rsync_opts[@]}" source/ target
上記のすべての変数拡張では、参照が重要です。拡張"${array[@]}"
(および"$@"
その下)は、関連する配列の個別に引用された要素のリストを生成します(ただし、二重引用符の中にのみ適用されます!)。
すべての/bin/sh
シェルの場合:
set -- '/home/*/.cache/*' \
'/var/cache/*' \
'/var/tmp/*' \
'/var/lib/lxcfs/cgroup/*'
for excl do
set -- "$@" --exclude="$excl"
shift
done
set -- --verbose --archive "$@"
rsync "$@" source/ target