Bash 使用eval通过ssh运行sqlite时出现语法错误

Bash 使用eval通过ssh运行sqlite时出现语法错误,bash,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 loo

当我想在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:

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


看起来它的结尾有一个额外的引号
,如果是这样,解释器会认为它是一个新的(但未终止的)字符串的开始

你的情况已经相当复杂了。不要试图将
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"
这就是说,将代码保存在字符串中并
评估它们是而不是最佳实践。取而代之的是,考虑使用函数作为局部评估的一部分:

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
}

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

想一想如果你的程序运行时带有一个参数
'$(rm-rf/)'
——你永远都不希望你的脚本能够运行
cd~/test/emane/gvine/node-$(rm-rf/)
;使用
printf%q
构建eval-safe字符串可确保内容始终安全转义


下一个问题:为什么将一些东西(如
>out.csv
放在
printf%q
的外部)作为常量是安全的?因为:

  • 这些片段包含shell语法,
    printf%q
    将通过安全转义转换为数据,使它们不再作为shell的指令
  • 数据组件是常量。如果
    out.csv
    改为
    $2.csv
    ,那么我们希望使用
    printf%q
    来转义
    “$2”
    部分

另外,BashFAQ#50:通过ssh传递命令已经将它们暴露于一层
eval
处理中。在上面加上第二个是把已经很容易出错的东西混合起来。这是真的,但它甚至还没有接近问题的全部。
run_remote_sql 10