这是我第一次使用真正的bash脚本,而且我在扩展和引用方面遇到了很大麻烦。
如果给出参数-t,我正在编写一个测试ssh连接和一些远程mysql命令的脚本,如果给出参数-r,则在真实的远程服务器上使用它们。我想将ssh和mysql命令的选项存储到变量中,因此当给出-r或-t时,它使用相同的例程。
长话短说,剧本或多或少看起来像这样:
sql="SELECT id FROM user WHERE (email LIKE '%a@b.com' OR email LIKE '%c@d.com');"
case "$1" in
-t )
ssh_opts=(localhost -i ~/.ssh/id_rsa)
mysql_opts=(-u root --password=password test);;
-r )
ssh_opts=("-oCheckHostIP no" "-oCompression yes" "-oProtocol 2" "-oProxyCommand connect -4 -S localhost:9050 $(tor-resolve remoteip localhost:9050) 22" remoteip -i ~/.ssh/id_rsa -l httpd)
mysql_opts=('-h mysqlserver' '-P 3306' '-u user' '--password=password' database) -t );;
esac
read -a ids < <(ssh "${ssh_opts[@]}" \"mysql "${mysql_opts[@]" --disable-column-names -B -e \"$'${sql}'\""\")
csv_ids=$(IFS=,; echo "${ids[*]}")
你可能已经注意到我在这一点上非常迷茫,我觉得这太复杂了。任何人都可以分享一些如何正确做到这一点的提示吗?
谢谢
答案 0 :(得分:2)
在这部分之前,你的表现并不是那么糟糕:
read -a ids < <(ssh "${ssh_opts[@]}" \"mysql "${mysql_opts[@]" --disable-column-names -B -e \"$'${sql}'\""\")
要生成mysql命令,请使用printf %q
引用它们,然后使用printf %q
为您正确引用的字符串:
printf -v mysql_opts_str '%q ' "${mysql_opts[@]}"
ssh "${ssh_opts[@]}" "mysql $mysql_opts_str ..."
原始表单不起作用,因为\"foo bar\"
被解析为两个参数:"foo
和bar"
;转义时,引号被视为数据,而不是语法。
那就是说--bash通常是用于与SQL交互的错误工具;它不提供解析任意表内容的工具(因此您最终会对查询结果做出假设),也不提供将任意字符串作为绑定变量传递的工具。 (我曾经用这种支持编写了一个命令行Oracle客户端,供shell脚本使用,但它从未公开发布)。你应该认真考虑使用更适合这项工作的工具。