这个问题在这里已经有了答案:为什么shell会忽略通过变量传递给它的参数中的引号字符? [重复] (3个回答) 6年前关闭。
我尝试执行以下命令:
mysql AMORE -u username -ppassword -h localhost -e "SELECT host FROM amoreconfig"
我将它存储在一个字符串中:
cmd="mysql AMORE -u username -ppassword -h localhost -e\"SELECT host FROM amoreconfig\""
测试它:
echo $cmd
mysql AMORE -u username -ppassword -h localhost -e"SELECT host FROM amoreconfig"
尝试执行:
$cmd
我得到了 mysql 的帮助页面:
mysql Ver 14.14 Distrib 5.1.31, for pc-linux-gnu (i686) using readline 5.1
Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL license
Usage: mysql [OPTIONS] [database]
(...)
我想我对引号做了一些明显的错误,但无法找出问题所在。
declare -f
打印其文本;对于数组(典型的“动态构造”方法):printf '%q ' "${array[@]}"; echo
。
eval
,就像这里的最佳答案一样,会带来巨大的安全风险(如果任何内容被参数化,则会面临 shell 注入攻击)。
你有没有尝试过:
eval $cmd
对于如何转义 *
的后续问题,因为它在裸露或双引号字符串中具有特殊含义:使用单引号。
MYSQL='mysql AMORE -u username -ppassword -h localhost -e'
QUERY="SELECT "'*'" FROM amoreconfig" ;# <-- "double"'single'"double"
eval $MYSQL "'$QUERY'"
奖励:它也读起来不错:eval mysql query ;-)
按照 BashFAQ #50 中的指导使用数组,而不是字符串。
使用字符串是非常糟糕的安全做法:考虑用户提供 password
(或查询中的 where 子句或任何其他组件)的情况;您不想eval
包含 $(rm -rf .)
的密码!
只运行一个本地命令
cmd=( mysql AMORE -u username -ppassword -h localhost -e "SELECT host FROM amoreconfig" )
"${cmd[@]}"
明确地打印您的命令
cmd=( mysql AMORE -u username -ppassword -h localhost -e "SELECT host FROM amoreconfig" )
printf 'Proposing to run: '
printf '%q ' "${cmd[@]}"
printf '\n'
通过 SSH 运行命令(方法 1:使用标准输入)
cmd=( mysql AMORE -u username -ppassword -h localhost -e "SELECT host FROM amoreconfig" )
printf -v cmd_str '%q ' "${cmd[@]}"
ssh other_host 'bash -s' <<<"$cmd_str"
通过 SSH 运行命令(方法 2:命令行)
cmd=( mysql AMORE -u username -ppassword -h localhost -e "SELECT host FROM amoreconfig" )
printf -v cmd_str '%q ' "${cmd[@]}"
ssh other_host "bash -c $cmd_str"
cmd+=( -e "$query" )
将这些参数附加到现有数组,并确保 query
将作为单个参数添加到 -e
并传递给 mysql
;无需查看它的内容来确定它是否生成子外壳或转义其引号并启动 rootkit 或其他任何东西。
尝试这个
$ cmd='mysql AMORE -u root --password="password" -h localhost -e "select host from amoreconfig"'
$ eval $cmd
eval "$cmd"
而不是 eval $cmd
,以处理任何分词组件可以全局扩展为当前目录中的文件的情况,或者 IFS 中的字符无法无害地替换其他字符的情况。
你甚至不需要“eval”。只需在字符串前面放一个美元符号:
cmd="ls"
$cmd
`$cmd`
要消除对 cmd 变量的需要,您可以这样做:
eval 'mysql AMORE -u root --password="password" -h localhost -e "select host from amoreconfig"'
eval
而不是只运行 mysql [...]
?
eval
语句中的文字引号,当它们通过使用eval
成为语法时,可以通过数据中的任何文字引号取消其效果;因此,它们不能提供有效的安全性。eval $cmd
与eval "$cmd"
不同,它将您的输入拆分为单词,将每个单词评估为一个 glob,然后将它们与空格一起粘贴回来,所以一个带有空格环绕星号的命令可能会导致当前工作目录的文件名中的 shell 扩展被评估)。