2013-07-03 59 views
3

我想争论从这样的变量传递给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

在这种特殊情况下,您可以使用'MYOPTS =“ - essh -p1234”'然后'rsync“$ MYOPTS”192.168.0.1:/a/a'。但总的来说,值得学习如何做到这一点。看到各种答案。 (我会去的阵列,但YMMV。) – rici

+2

[我试图把一个命令在一个变量,但复杂的情况下总是失败](http://mywiki.wooledge.org/BashFAQ/050) –

回答

2

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

eval "rsync $MYOPTS 192.168.0.1:/a /a" 
+0

实际上这解决了这个问题,因为将'rsync $ MYOPTS 192.168.0.1:/a/ a'改为'eval'rsync $ MYOPTS 192.168.0.1:/a/a“'不会破坏旧的语法。 – AndreKR

9

它与方式猛砸做分裂的说法。现在,永远不要把命令和参数放在一个变量中。使用数组(而且,停止使用大写变量名称,它丑陋和危险,因为它可能与已定义的变量冲突)。而应该写:

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 

,你可能穿上” t想要:)

现在,变量$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 

…这可能是你想要的:)

希望这会有所帮助!

+0

+1的解释。不幸的是,所提出的解决方案打破了使用旧语法的脚本。我不清楚我可以更改rsync呼叫的方式,请参阅我更新的问题。 – AndreKR

+0

是的。我认为很遗憾bash的数组变量语法是如此klunky,但也许这是sh兼容性的价格。 (csh的数组变量是......不同的klunky,但csh本身只是shell脚本编码的噩梦)。这就是为什么我已经转向使用Python编写复杂脚本。 :-) – torek

+1

@AndreKR如果您正在为Bash编程,请修改您的脚本,以便它可以一直处理这个“myopts”的数组。从长远来看这真的很值得!如果你完全阅读我的文章,你可能会知道如何安全地使用':)'。 –