String 带双引号的参数列表在Bash中无法正确传递

String 带双引号的参数列表在Bash中无法正确传递,string,bash,String,Bash,我有一个Bash脚本,它调用另一个Bash脚本。被调用的脚本会对一些事情进行一些修改和检查,并进行移位,然后将调用方的其余命令行传递给其他人 在被调用的脚本中,我已经验证了我已经管理好了所有的东西并准备好了调用。下面是我输入的一些调试风格的代码: echo $SVN $command $@ > /tmp/shimcmd bash /tmp/shimcmd $SVN $command $@ 现在,在/tmp/shimcmd中,您将看到: svn commit --username=myus

我有一个Bash脚本,它调用另一个Bash脚本。被调用的脚本会对一些事情进行一些修改和检查,并进行移位,然后将调用方的其余命令行传递给其他人

在被调用的脚本中,我已经验证了我已经管理好了所有的东西并准备好了调用。下面是我输入的一些调试风格的代码:

echo $SVN $command $@ > /tmp/shimcmd
bash /tmp/shimcmd
$SVN $command $@
现在,在/tmp/shimcmd中,您将看到:

svn commit --username=myuser --password=mypass --non-interactive --trust-server-cert -m "Auto Update autocommit Wed Apr 11 17:33:37 CDT 2012"
也就是说,构建的命令,都在一行中,非常好,包括-m“mystringwithspaces”部分

太完美了。而且它的“bash/tmp/shimcmd”执行也非常有效

但我当然不想要这个愚蠢的tmp文件之类的(只用于调试)。问题是直接调用命令,而不是通过垫片文件:

$SVN $command $@
结果svn命令本身没有接收带空格的带引号的字符串——它将'-m“my string with spaces”'参数弄乱,并将命令作为'-m my string with spaces'传递

我尝试过各种疯狂的逃跑方法,但都没有成功。真不敢相信它这么缠着我。同样,通过向文件回显相同的内容($SVN$command$@),然后执行该文件,就可以了。但是直接调用会弄乱引用的字符串。单凭这一点就足以说明问题

有什么想法吗


Dan

以下是一种证明问题的方法:

$ args='-m "foo bar"'
$ printf '<%s> ' $args
<-m> <"foo> <bar">
$args='-m“foo-bar”
$printf''$args
这里有一个避免的方法:

$ args=( -m "foo bar" )
$ printf '<%s> ' "${args[@]}"
<-m> <foo bar>
$args=(-m“foo-bar”)
$printf“”“${args[@]}”
在后一种情况下,args是一个数组,而不是带引号的字符串

请注意,顺便说一句,必须是“$@”,而不是“
$@
”,才能获得此行为(在这种情况下,为了尊重数组项的边界,避免了字符串拆分)。

您尝试过:

eval "$SVN $command $@"

这个

echo -n -e  $SVN \"$command\"  > /tmp/shimcmd
for x in "$@"
  do
     a=$a" "\"$x\"
  done
echo -e " " $a >> /tmp/shimcmd
bash /tmp/shimcmd
或者干脆

$SVN "$command" "$@"

你能发布一些具体的步骤来获得这种行为吗?我很难重现这个问题。@jimw这是一个非常常见的反模式——基本上,你不能指望字符串拆分来做正确的事情;他应该用数组来代替。非常正确。通常我可以通过摆弄来挑出这些引用问题,但如果我们谈论的是良好的编程实践,那么你是绝对正确的。我必须承认,当我在bash脚本中需要数组时,我通常会使用perl或python.Presto!简单地添加“eval”:eval“$SVN$command$@”就成功了。很好用!非常感谢您提供的所有想法--现在将使用简单的git-er评估。@user1327769请不要这样做。如果处理不可信的输入,使用eval是非常不安全的,而使用数组则可以安全地处理这些情况。请参阅任何符合POSIX标准的外壳中的上述工作。这个问题的基本思想是运行存储在各种变量之间的命令。如果您不信任该命令的内容,那么整个方法就是错误的。例如,如果有人可以操纵
$SVN
,这样它就可以
rm-rf/
(您是root用户),那么避免eval对您没有帮助。此特定脚本位于一个控制良好、无人参与、自动化的环境中,不会与任何用户或用户输入交互。这就是说,当然,它不是没有风险的,但风险级别很低。如果您想安全地转义字符串,
printf%q
是标准的方法,而不是像这样写一堆意大利面条。当然,“标准”的值不等于“便携”或“POSIX标准”。它可能是一种方便的方式,或者GNU-y方式,但是canonical有点像一个加载的单词。