私のシェルはzshです。 Bashでこのコマンドを試しましたが、うまくいきました。
ignore_files=(
local
\*.local.\*
.bundle
Gemfile.lock
)
ignore_command=""
for f in "${ignore_files[@]}"; do
ignore_command="$ignore_command -x $f"
done
echo $ignore_command
# print: -x local -x *.local.* -x .bundle -x Gemfile.lock
sudo diff -ruNd $ignore_command <path a> <path-b>
# failed: diff: extra operand '<path-b>'
echo sudo diff -ruNd $ignore_command <path a> <path-b>
# sudo diff -ruNd -x local -x *.local.* -x .bundle -x Gemfile.lock <path a> <path-b>
eval diff -ruNd $ignore_command <path a> <path-b> # success
変数がコマンドで拡張されていないようです。 evalなしでbashのようにする理由と方法を知りたいです。
答え1
コマンドはパラメータのリストであり、配列を使用してこれらのパラメータを保存しようとします。
ignore_files=(
local
'*.local.*'
.bundle
Gemfile.lock
)
ignore_command=()
for f in "${ignore_files[@]}"; do
ignore_command+=(-x "$f")
done
print -r -- "${(q+)ignore_command[@]}"
sudo diff -ruNd "${ignore_command[@]}" <path a> <path-b>
Bourneのようなシェルの動作のために混乱する可能性があります。ここで引用符で囲まれていない引数拡張は分割+グローブ演算子なので、文字列/スカラー変数をリスト(またはパターンに一致するファイル)に変換します。拡張後。
この誤った動作は、zsh
のような他のほとんどの最新のシェルによって修正されましたrc
。es
fish
を使用してBourneシェルの動作をシミュレートできますが、set -o shwordsplit -o globsubst
これは回帰を引き起こします。特にあなたの場合、グローバル文字が含まれているためglobsubst
問題が発生します。*.local.*
でzsh
変数を分割したり、拡張時にワイルドカードを実行したりするには、明示的に要求する必要があります。
$=var
、文字$var
で区切ります$IFS
。${(s:,:)var}
特定の文字列に基づいて分割(ここ,
)$~var
:拡張時にワイルドカードの指定(またはコンテキストに応じてパターンマッチング)を行います。 (たとえば、Contains$var
の場合、リストコンテキストはBourneシェルのように現在のディレクトリのファイルリストに展開されます。)*
$~var
$var
$=~var
$var
:Bourneシェルと同様に、分割とワイルドカードを同時に実行します。
この特別なケースでは、次のこともできます。
sudo diff -ruNd --exclude=$^ignore_files <path a> <path-b>
(^
アレイがinfish
または...rc
のように拡張されている場合は、実際にはアクティブ化などの対応する拡張オプションを--exclude=element1
--exclude=element2
有効にします)。rcexpandparam
~
globsubst
=
shwordsplit