作为命令的一部分转义文字星号

时间:2015-02-23 19:42:51

标签: bash

示例bash脚本

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

我收到错误,因为*在我的CWD中被评估为glob(枚举)文件。

我看过其他帖子谈到引用" $ CMD"用于回声输出的参考,但在这种情况下

"$CMD"

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

如果我

echo "$CMD"

然后将其复制/粘贴到命令行,似乎工作正常。

2 个答案:

答案 0 :(得分:4)

你可以使用:

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

这不会受到* shell的扩展。

如果您还要存储mysql命令行,请使用BASH数组:

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

答案 1 :(得分:1)

注意: anubhava's answer有正确的解决方案 这个答案提供了背景信息。

至于为什么你的方法不起作用:

"$CMD"无法正常工作,因为bash将整个值视为单个令牌,并将其解释为命令名称,这显然会失败


`$CMD` 

,即将$CMD括在反引号中,在这种情况下是没有意义的(如果命令产生stdout输出 [1] ,则会产生意想不到的副作用);只使用:

$CMD

产生相同的 - 破坏 - 结果(只是更有效 - 通过封闭反引号,你不必要地创建一个子shell;使用反引号 - 或者更好,$(...)只有在另一个中嵌入一个命令 - 见command substitution)。


$CMD无效,

  • 因为*的无引号使用使其受到路径扩展(globbing) - 以及其他shell扩展。
  • \ - 逃离水族字符。在执行字符串时,字符串会导致\ 保留

虽然似乎,但您已将*用双引号括起来(间接)放在转义双引号之间({{ 1}})在双引号字符串中, shell执行查看这些转义双引号之间的内容,作为单个双引号字符串

相反,这些双引号成为它们所邻接的标记的 literal 部分,而shell仍然在字符串上执行单词拆分(通过空格解析成单独的参数),和扩展,例如对生成的标记进行全球化。

如果我们假设关闭了globbing(通过\"$QRY\"),那么当shell评估(未引用)set -f时,传递给mysql的参数的细分:

  • $CMD - 所有剩余的参数都是无意中拆分的SQL命令。
  • -e # $1 - 请注意"select # $2已成为参数
  • 的字面部分
  • "
  • * # $3
  • from # $4 - 请注意mysql" # $5已成为参数
  • 的字面部分

让您的解决方案使用现有的单字符串变量的唯一方法是使用",如下所示:

eval

这样,嵌入的转义双引号字符串被正确解析为单个双引号字符串(没有应用通配符),(在引用删除之后)作为单个参数传递给{{1} }。

但是,由于其安全隐患, eval "$CMD" 通常应避免(如果您不完全控制字符串的内容,则任意命令可以被执行)。

再次,请参考anubhava's answer以获得正确的解决方案。


[1]使用mysql作为命令的注释:
它导致bash从eval 执行 stdout输出作为另一个命令,这很少是意图,并且通常会导致命令损坏,或者更糟糕的是,具有意想不到的效果的命令 尝试运行`$CMD`反引号 - 与$CMD相同);你得到`echo ha`,因为bash试图执行命令输出 - $(echo ha) - 作为命令失败。 功能