以下のスクリプトはbashでは機能しますが、zshでは機能しません。私はこれが変数内でOPTS
変数を「拡張」(正しい単語かどうかわからない)していて、この構文が$EXCLUDE
zshでは機能しないためだと思います。 zshで動作するようにこの行をどのように変更できますか?
SRC="/path_to_source"
DST="/path_to_dest"
EXCLUDE=".hg"
OPTS="-avr --delete --progress --exclude=${EXCLUDE} --delete-excluded"
rsync $OPTS $SRC $DST
答え1
ここでの問題は、$OPTS
コマンドラインで複数のパラメータに区別されないことですrsync
。zsh
構文では、次を使用します。
rsync ${=OPTS} $SRC $DST
(代替は、オプションを使用してグローバルに標準シェル動作をエミュレートすることです-o shwordsplit
...)
マンページから:
[in]の一般的な違い
zsh
は、コマンドラインで置き換えられた変数が単語に分割されないことです。SH_WORD_SPLIT
「パラメータ拡張」セクションのシェルオプションの説明を参照してくださいzshexpn(1)
。では、zsh
明示的に分割を要求したり(たとえば${=foo}
)、変数を複数の単語に拡張したい場合は、配列を使用できます。の「配列パラメータ」を参照してくださいzshparam(1)
。
答え2
問題は、では$EXCLUDE
なくで発生します$OPTS
。あなたのスクリプトは単語分離の発生に依存します$OPTS
。たとえば、現在のディレクトリに$EXCLUDE
パターンと一致ファイルを含めるように変更したり、スペースを含めるように変更すると--exclude=$EXCLUDE
失敗$EXCLUDE
します。
$OPTS
単一の単語ではなく単語のリストです。 ksh、bash、zshでのみ動作するスクリプトが必要な場合は、それを配列にします。
SRC="/path_to_source"
DST="/path_to_dest"
EXCLUDE=".hg"
OPTS=(-avr --delete --progress --exclude="$EXCLUDE" --delete-excluded)
rsync "${OPTS[@]}" "$SRC" "$DST"
スクリプトがzshでのみ機能するようにするには、最後の行を単純化するだけです。
rsync $OPTS $SRC $DST
すべてのシェルでスクリプトを実行するには、位置パラメータを使用する必要があります。これは利用可能な唯一の配列です。
set -- -avr --delete --progress --exclude="$EXCLUDE" --delete-excluded
rsync "$@" "$SRC" "$DST"
zshを使用してシェルスクリプトを簡単に実行するには、この行を先頭に配置します。これはzshがkshのように動作し、他のシェルでは何もしないように指示します。
emulate ksh >/dev/null 2>/dev/null || true
答え3
zsh
Stéphane Gimenezの答えを完了するには(まだコメントできません)、1つの解決策はスクリプトを使用していることを$OPTS
確認してから、次の配列に変換してスクリプトをbashに移植可能にすることです。
[ -n "${ZSH_VERSION:-}" ] && set -A OPTS ${=OPTS}
これで rsync コマンドが動作します。