使用eval在ssh上运行sqlite的语法错误

时间:2015-08-11 22:19:57

标签: bash

当我想在bash脚本中运行此sqllite3命令时,我收到错误消息。 我将不胜感激。

DB_CMD="ssh -X node-11 \"cd ~/test/emane/gvine/node-10/ && sqlite3 -header -csv emane_data.db \"select * from rxfile;\" >>./out.csv\\"""
eval $DB_CMD

eval: line 56: unexpected EOF while looking for matching `"' eval: line 57: syntax error: unexpected end of file
sqlite3: Error: too many options:

2 个答案:

答案 0 :(得分:2)

你已经有了相当复杂的情况。不要试图将eval扔进混合物中,或者至少让shell本身完成构建引用的工作。

# put a shell-quoted version of your sqlite command into sqlite_cmd_str
printf -v sqlite_cmd_str '%q ' sqlite3 -header -csv emane_data.db "select * from rxfile;"

# substitute that into remote_cmd_str
remote_command_str="cd ~/test/emane/gvine/node-10/ && ${sqlite_cmd_str} >>out.csv"

# ...now, run that remote command...
ssh -X node-11 "$remote_command_str"

# ...or, if you **really** want to use eval:
printf -v local_cmd_str '%q ' ssh -X node-11 "$remote_command_str"
eval "$local_cmd_str"

这就是说 - 在字符串中保存代码并eval对其进行保存是最佳做法。相反,请考虑使用函数进行本地评估:

run_remote_sql() {
  local sqlite_cmd_str remote_cd_cmd_str remote_cmd_str
  local node_num=$1

  printf -v sqlite_cmd_str '%q ' \
    sqlite3 -header -csv emane_data.db "select * from rxfile;"
  printf -v remote_cd_cmd_str '%q ' \
    cd "test/emane/gvine/node-$1"
  remote_cmd_str="$remote_cd_cmd_str && $sqlite_cmd_str >>out.csv"
  ssh -X "node-$1" "$remote_cmd_str"
}

...定义一个可以调用的函数:

run_remote_sql 10

或者,在远程端进行参数管理:

run_remote_sql() {
  printf -v extra_args '%q ' "$@"
  ssh -X node-"$1" "bash -s $extra_args" <<'EOF'
cd ~/test/emane/gvine/node-"$1"/ || exit
sqlite3 -header -csv emane_data.db "select * from rxfile;" >>./out.csv
EOF
}

...再次......

run_remote_sql 10

现在,为什么所有printf %q?首先,这意味着您不需要自己进行所有引用(您可能已经注意到,正确引用多个嵌套评估级别很难!)。第二:安全原因。

考虑如果您的程序使用'$(rm -rf /)'参数运行会发生什么 - 您不希望脚本能够运行cd ~/test/emane/gvine/node-$(rm -rf /);使用printf %q构建eval-safe字符串可确保始终安全地转义内容。

下一个问题:为什么将>>out.csvprintf %q之外的作为常量放一些东西是安全的?这是因为:

  • 这些部分包含shell语法,printf %q将通过安全转义 - 变成数据,使它们不再被shell视为指令。
  • 数据组件是常量。如果out.csv改为$2.csv,那么我们希望使用printf %q来逃避"$2"部分。

答案 1 :(得分:0)

命令的这一部分:./out.csv\"""

在最后看起来它是一个额外的引用",如果是这样,解释器认为它是一个新的(但未终止的)字符串的开头。