2015-02-23 42 views
2

样品bash脚本逃离文字星号作为命令

QRY="select * from mysql" 
CMD="mysql -e \"$QRY\"" 
`$CMD` 

我得到的错误,因为*是越来越为水珠(枚举)的文件在我的CWD评估的一部分。

我已经看到了谈报价回声输出的目的,“$ CMD”参考其他职位,但在这种情况下

"$CMD"

抱怨整个文字字符串作为命令。

如果我

echo "$CMD" 

然后复制/粘贴到命令行中,事情似乎工作。

+0

'\ *'或者用单引号包装查询。 – bishop 2015-02-23 19:45:20

+1

然后,它似乎是作为CMD的一部分而出现的字面\ *,而不是根据需要转义 – atxdba 2015-02-23 19:49:53

+0

@cerebriform:在此情况下,没有引用变化可以提供帮助。问题是你不能在另一个字符串中嵌入(转义的)带引号的字符串,并且使用简单的变量扩展('$ CMD')将嵌入的字符串识别为这样;看到我的答案更多。 – mklement0 2015-02-23 21:19:21

回答

4

你可以使用:

qry='select * from db' 
mysql -e "$qry" 

这不会受到*扩张的外壳。

如果你想存储mysql命令行也然后使用BASH阵列:

cmd=(mysql -e "$qry") 
"${cmd[@]}" 
1

注:anubhava's answer有合适的解决方案。
此答案提供背景信息。

至于为什么你的方法没有奏效:

"$CMD"不起作用,因为bash中看到整个价值为令牌,它解释为命令名称,这显然会失败。


`$CMD` 

即,在反引号包围$CMD,是没有意义的在这种情况下(并且将具有意想不到的副作用,如果命令产生标准输出输出[1]);仅使用:

$CMD 

产生相同的 - 只有更有效的结果( - - 断通过在反引号包围,则不必要地创建子外壳;使用反引号 - 或,更好,$(...)另一个嵌入一个命令仅当 - 见command substitution)。


$CMD不起作用,

  • 因为不带引号的使用*科目它路径扩展(通配符) - 其他shell扩展中。
  • \ - 转义glob字符。在字符串中导致\保留当字符串执行时。

虽然它可能似乎,你已经通过将其放置(间接)之间的双引号字符串内的转义双引号(\"$QRY\")双引号括起来的*,在外壳程序查看这些转义双引号之间的单引号字符串

相反,这些双引号成为字面份令牌它们邻接的,并且壳仍然执行字分裂(解析成由空格分开的参数)上的字符串,和扩展诸如通配符上所得到的标记。

如果我们假设为通配符被关闭(通过set -f)了一下,这里是传递给mysql参数的故障时,壳求值(不带引号)$CMD

  • -e # $1 - 所有剩余的参数是无意间拆分的SQL命令。
  • "select # $2 - 注意"已成为争论
  • * # $3
  • from # $4
  • mysql" # $5的文本部分 - 注意,"已经成为争论的文本部分

的只有使用才能让您的解决方案与现有的单个字符串变量一起工作如下:

eval "$CMD" 

这样,嵌入式逃脱双引号字符串被正确解析为单,双引号字符串(到没有被施加通配),其中(后引用删除)的传递一个参数为mysql

然而,eval通常是要避免由于它的安全隐患(如果你不(完全)控制字符串的内容,任意的命令可以执行)。

同样,请参阅anubhava's answer以获得正确的解决方案。


[1]的说明重新使用`$CMD`如通过本身的命令:
它可使bash从$CMD执行标准输出输出作为另一命令,这是很少的意图,并且一般将导致命令中断,或者更糟糕的是,命令带来意想不到的效果。
尝试运行`echo ha`反引号 - 与$(echo ha)相同);你会得到-bash: ha: command not found,因为bash试图执行命令的输出 - ha - 作为命令失败。

+0

eval比反引号更安全吗? – atxdba 2015-02-24 05:28:47

+0

@atxdba:是的,因为eval允许将命令注入到仅仅是可变扩展不会执行的字符串中。考虑'v ='日期;回声注入命令'。 '$ v'会失败(它将所有的标记作为_single_命令处理),而'eval“$ v”'会将字符串解析为命令行并执行注入的命令。如果你完全控制你传递给它的字符串的创建,使用'eval'是可以接受的,但是使用'eval'是一个危险的习惯。在大多数情况下,当然在这种情况下,存在安全的替代方案。 – mklement0 2015-02-24 15:47:40