我正在尝试对小型数据库运行 sqlite3 查询来更新表。虽然脚本更复杂,但为了测试我设置了以下变量:
DN=123
UP=123
downlocalip=10.1.2.3
downremoteip=123
uplocalip=123
upremoteip=123
然后我运行以下命令来更新表。
sqlite3 /var/www/server/newserverstats.db "UPDATE stats SET downspeed='''$DN''', upspeed='''$UP''', downlocalip='''$downlocalip''', downremoteip='''$downremoteip''', uplocalip='''$uplocalip''', upremoteip='''$upremoteip''' WHERE primkey=1"
这会引发语法错误:
Error: near ".2": syntax error
如果我设置下本地ip仅作为 10.1,它工作得很好,所以它不喜欢额外的小数。
在表格本身上,我将类型设置为文本,所以我认为这并不重要?
表的编译指示输出:
0|primkey|integer|0||1
1|downspeed|integer|1||0
2|upspeed|integer|1||0
3|downlocalip|text|1||0
4|downremoteip|text|1||0
5|uplocalip|text|1||0
6|upremoteip|text|1||0
我尝试了各种引号设置,但看不出我做错了什么。
有任何想法吗?
编辑:
我根据下面的评论尝试过的完整命令是:
/usr/bin/ssh [email protected] 'sqlite3 /var/www/server/newserverstats.db "UPDATE stats SET downspeed=$DN, upspeed=$UP, downlocalip="$downlocalip", downremoteip="$downremoteip", uplocalip="$uplocalip", upremoteip="$upremoteip" WHERE primkey=1"'
或者
/usr/bin/ssh [email protected] 'sqlite3 /var/www/server/newserverstats.db "UPDATE stats SET downspeed=$DN, upspeed=$UP, downlocalip='$downlocalip', downremoteip='$downremoteip', uplocalip='$uplocalip', upremoteip='$upremoteip' WHERE primkey=1;"'
两者都给我以下错误:
Error: near ",": syntax error
新命令,更接近:
ssh [email protected] sqlite3 /var/www/server/newserverstats.db <<END_SQL
UPDATE stats
SET downspeed=$DN,
upspeed=$UP,
downlocalip="$downlocalip",
downremoteip="$downremoteip",
uplocalip="$uplocalip",
upremoteip="$upremoteip"
WHERE primkey=1
END_SQL
折叠回测试脚本中的一行:
#!/bin/bash -x
DN=123
UP=123
downlocalip=10.1.2.3
downremoteip=123
uplocalip=123
upremoteip=123
sql="UPDATE stats SET downspeed=$DN, upspeed=$UP, downlocalip="$downlocalip", downremoteip="$downremoteip", uplocalip="$uplocalip", upremoteip="$upremoteip" WHERE primkey=1"
echo $sql
ssh [email protected] sqlite3 /var/www/server/newserverstats.db "$sql"
这给了我以下回应:
UPDATE stats SET downspeed=123, upspeed=123, downlocalip=10.1.2.3, downremoteip=123, uplocalip=123, upremoteip=123 WHERE primkey=1
sqlite3: Error: too many options: "stats"
Use -help for a list of options.
答案1
问题在于文本字段中字符串的引用。
使用此处文档(它使您能够编写更美观的语句):
sqlite3 database <<END_SQL
UPDATE stats
SET downspeed=$DN,
upspeed=$UP,
downlocalip="$downlocalip",
downremoteip="$downremoteip",
uplocalip="$uplocalip",
upremoteip="$upremoteip"
WHERE primkey=1
END_SQL
这是假设您可以完全控制变量中的值,以便您知道它们已被正确清理并且不会引入任何 SQL 注入漏洞。
来自评论:
通过 SSH 执行此操作:
ssh user@server sqlite3 database <<END_SQL
UPDATE stats
SET downspeed=$DN,
upspeed=$UP,
downlocalip="$downlocalip",
downremoteip="$downremoteip",
uplocalip="$uplocalip",
upremoteip="$upremoteip"
WHERE primkey=1
END_SQL
答案2
主要问题是您在每个变量之前和之后使用了三个单引号,而不是仅一个。这是没有必要的——事实上,这是行不通的。
您在 IP 地址上收到错误,$downlocalip
因为它实际上未加引号,因此 sqlite3 尝试将其解释为浮点数而不是文本字符串......并且浮点数中没有两个小数点。
另一个小问题是您在整数字段 (downspeed
和upspeed
) 的值两边加上单引号。
试试这个:
sqlite3 /var/www/server/newserverstats.db "UPDATE stats SET downspeed=$DN,
upspeed=$UP, downlocalip='$downlocalip', downremoteip='$downremoteip',
uplocalip='$uplocalip', upremoteip='$upremoteip' WHERE primkey=1;"
该字符串中的单引号是里面双引号,因此不会阻止 shell 扩展变量。它们在双引号内没有特殊含义,它们只是文本的一部分。双引号内的变量确实具有特殊含义,因此请按照您的预期进行扩展。
或者使用 Kusalananda 的答案中的heredoc - 它更具可读性。
顺便说一句,如果您正在进行大量 sqlite 操作,那么最好使用具有支持占位符值的 sqlite 库模块的语言来编写脚本。例如,两者perl
都有python
出色的库用于处理 sqlite3 和其他 SQL 数据库。您通常可以使用这些库编写代码,这样它们只需进行很少的更改(如果有的话)即可与其他数据库(例如 postgresql 或 mysql)一起使用。