3

我想rsync从这样的变量传递一个参数:

myopts='-e "ssh -p 1234" -a'
rsync $myopts 192.168.0.1:/a /a

由于某种原因,这不起作用。我什至发现这个网页说它不起作用:

### NO NO NO: this passes three strings:
###      (1)  "my
###      (2)  multiword
###      (3)  argument"
MYARG="\"my multiword argument\""
somecommand $MYARG

### THIS IS NOT (!!!!) THE SAME AS ###
command "my multiword argument"

### YOU NEED ###
MYARG="my multiword argument"
command "$MYARG"

不幸的是,它没有说明为什么它不起作用。

包含rsync调用的脚本被很多其他脚本使用,所以我只能以兼容的方式更改它。一个不起作用的解决方案是使用数组:

myopts=('-a' '-v' '-z') # new way, would work
myopts='-a -v -z'       # old way, breaks
rsync "${myopts[@]}" 192.168.0.1:/a /a

变量中的选项被完全忽略。

4

2 回答 2

9

这与 Bash 拆分论点的方式有关。现在,永远,永远不要将命令和参数放在一个变量中。改用数组(而且,停止使用大写变量名,这既丑陋又危险,因为它可能与已定义的变量发生冲突)。你应该写:

myopts=( -e "ssh -p 1234" )
rsync "${myopts[@]}" 192.168.0.1:/a /a

在这种情况下,rsync将使用以下参数启动:

-e
ssh -p 1234
192.168.0.1:/a
/a

这可能是你想要的。


至于它为什么这样工作:假设

myopts='-e "ssh -p 1234"'

也就是说,myopts是以下字符串:

-e "ssh -p 1234"

未引用,Bash 将看到四个令牌。您可以这样检查:在终端中执行以下操作:

$ myopts='-e "ssh -p 1234"'
$ printf 'Token: %s\n' $myopts
Token: -e
Token: "ssh
Token: -p
Token: 1234"

所以当你启动时

rsync $myopts 192.168.0.1:/a /a

然后就像rsync使用这些参数启动:

-e
"ssh
-p
1234"
192.168.0.1:/a
/a

你可能不想要那个:)

现在,变量$myopts quoted只是一个记号:

-e "ssh -p 1234"

因此,如果您启动(注意引号):

rsync "$myopts" 192.168.0.1:/a /a

这就像rsync用这些论点启动:

-e "ssh -p 1234"
192.168.0.1:/a
/a

你也不希望那样。

确实,解决这个问题的最可靠的方法是使用 Bash 数组。看:将数组 myopts定义为(在终端中执行):

$ myopts=( -e "ssh -p 1234" )
$ # myopts is an array with two arguments. Check this (observe the quotes):
$ printf "Argument: %s\n" "${myopts[@]}"
Argument: -e
Argument ssh -p 1234
$ # Just for fun, what if we don't quote myopts?
$ printf "Argument: %s\n" ${myopts[@]}
Argument: -e
Argument: "ssh
Argument: -p
Argument 1234"

所以现在,我想你明白为什么会这样了:

rsync "${myopts[@]}" 192.168.0.1:/a /a

就像rsync使用这些参数启动:

-e
ssh -p 1234
192.168.0.1:/a
/a

……这可能就是你想要的:)

希望这可以帮助!

于 2013-07-03T19:44:19.437 回答
2

在变量扩展之后,唯一完成的处理是分词和通配符扩展(如果变量在双引号内,这些都不会完成),而不是引号处理。eval如果要重做命令行解析的所有步骤,则需要使用:

eval "rsync $MYOPTS 192.168.0.1:/a /a"
于 2013-07-03T19:43:53.167 回答