我的外壳是 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。
命令是参数列表,您想使用数组在此处存储这些参数:
您可能对 Bourne-like shell 的行为感到困惑,其中不带引号的参数扩展是 split+glob 运算符,因此它在扩展时将字符串/标量变量转换为列表(或匹配模式的文件) 。
这种不当行为已被
zsh
大多数其他现代 shell(如rc
,es
,fish
.您可以使用 来模拟 Bourne shell 的行为
set -o shwordsplit -o globsubst
,但这会倒退。具体来说,globsubst
在您的情况下会是一个问题,因为*.local.*
它包含全局字符。在
zsh
中,如果要拆分变量或在其展开时执行通配符,则必须明确询问:$=var
, 拆分字符$var
。$IFS
${(s:,:)var}
拆分特定字符串(此处,
)$~var
: 在展开时执行通配符(或模式匹配取决于上下文)(例如,如果$var
contains*
,$~var
在列表上下文中将展开到当前目录中的文件列表,如 Bourne shell 的$var
)$=~var
: 分裂和通配就像$var
Bourne shell 一样。在这种特殊情况下,您还可以执行以下操作:
(其中
^
导致数组像 infish
或rc
as一样扩展--exclude=element1
--exclude=element2
......它实际上启用了该rcexpandparam
扩展的选项,如enable和)。~
globsubst
=
shwordsplit