我想从这样的变量中将参数传递给rsync
:
myopts='-e "ssh -p 1234" -a'
rsync $myopts 192.168.0.1:/a /a
出于某种原因,这不起作用。我甚至发现this webpage说它无效:
### 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
完全忽略变量中的选项。
答案 0 :(得分: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
引用,只是一个标记:
-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
......这可能就是你想要的:)
。
希望这有帮助!
答案 1 :(得分:2)
在变量扩展之后,唯一的处理是分词和通配符扩展(如果变量在双引号内,这些都不会完成),而不是引用处理。如果希望重做命令行解析的所有步骤,则需要使用eval
:
eval "rsync $MYOPTS 192.168.0.1:/a /a"