在 zsh 中扩展变量

在 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   

答案1

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

rsync ${=OPTS} $SRC $DST 

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

从联机帮助页:

[in] 中常见的一个区别zsh是替换到命令行上的变量不会拆分为单词。请参阅SH_WORD_SPLIT中“参数扩展”部分中shell 选项的描述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

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

set -- -avr --delete --progress --exclude="$EXCLUDE" --delete-excluded
rsync "$@" "$SRC" "$DST"

如果您希望能够使用 zsh 方便地运行一个 shell 脚本,请将此行放在开头 — 它告诉 zsh 的行为类似于 ksh,并且在其他 shell 上是无操作的。

emulate ksh >/dev/null 2>/dev/null || true

答案3

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

[ -n "${ZSH_VERSION:-}" ] && set -A OPTS ${=OPTS}

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

相关内容