在 zsh 中扩展变量

Ame*_*ina 11 shell zsh

下面的脚本在 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   
Run Code Online (Sandbox Code Playgroud)

Sté*_*nez 22

这里的问题$OPTS是没有在rsync命令行上分成几个参数。在zsh语法中,使用:

rsync ${=OPTS} $SRC $DST 
Run Code Online (Sandbox Code Playgroud)

(另一种方法是使用选项全局模拟标准外壳行为-o shwordsplit......)

从联机帮助页:

[in zsh] 中常见的一个区别是,替换到命令行上的变量不会拆分为单词。见外壳选项的说明SH_WORD_SPLIT在部分“参数扩展” zshexpn(1)。在 中zsh,您可以显式请求拆分(例如${=foo}),也可以在希望将变量扩展为多个单词时使用数组。请参阅 中的“数组参数”部分 zshparam(1)


Gil*_*il' 10

问题不是来自$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"
Run Code Online (Sandbox Code Playgroud)

如果您只想让脚本在 zsh 中工作,您可以简化最后一行:

rsync $OPTS $SRC $DST
Run Code Online (Sandbox Code Playgroud)

如果您希望脚本在每个 shell 中工作,您需要使用位置参数。它们是唯一可用的阵列。

set -- -avr --delete --progress --exclude="$EXCLUDE" --delete-excluded
rsync "$@" "$SRC" "$DST"
Run Code Online (Sandbox Code Playgroud)

如果您有一个 shell 脚本,并且希望能够方便地与 zsh 一起运行,请将这一行放在开头——它告诉 zsh 像 ksh 一样运行,并且它在其他 shell 上是无操作的。

emulate ksh >/dev/null 2>/dev/null
Run Code Online (Sandbox Code Playgroud)


cbl*_*ard 6

要完成 St\xc3\xa9phane Gimenez 答案(我还不能发表评论),一种解决方案是通过检查您是否正在使用zsh然后将脚本转换$OPTS为这样的数组,使脚本可移植到 bash

\n\n
[ -n "${ZSH_VERSION:-}" ] && set -A OPTS ${=OPTS}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后你的 rsync 命令就可以工作了。

\n