You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

psql的\set命令无法存入JSON文件内容至变量的问题排查

为什么psql在bash脚本中用\set读取JSON文件只获取到第一个字符?

这个问题的核心是bash命令替换的分词行为和psql交互式执行的差异,我来帮你拆解清楚:

问题原因

当你在bash脚本的here-doc(<<EOF)里写\set var cat /tmp/jsonfile.json``时,bash会先对反引号里的命令输出做分词处理——它会把JSON内容里的空格、换行符都当作分隔符,把整个JSON拆成多个"字段"。比如你的JSON开头是{ "OT": [...] },bash会把它拆成{、"OT":、[...]等多个部分。

而psql的\set命令只会接受变量名和第一个值,所以最终var被设置成了第一个字段{,这就导致后续INSERT时JSON格式完全错误。

但你在psql提示符下手动执行时,是psql自己解析并执行命令替换,不会经过bash的分词步骤,所以能完整读取整个JSON文件的内容。

解决方案

这里有几个靠谱的解决办法,按推荐程度排序:

1. 使用psql参数化查询(最安全,避免SQL注入)

用psql的--variable参数传递JSON内容,完全绕开bash分词和引号转义的问题:

#!/bin/bash
# 先创建表(如果不存在的话)
psql -X -h localhost -U <dbuser> -d <dbname> -c "CREATE TABLE IF NOT EXISTS cardtable(id SERIAL PRIMARY KEY, charcolumn VARCHAR(20) NOT NULL, cardcolumn JSON NOT NULL);"

# 用参数化方式插入JSON
psql -X -h localhost -U <dbuser> -d <dbname> -c "INSERT INTO cardtable(charcolumn, cardcolumn) VALUES ('USA', :json_var);" --variable=json_var="$(cat /tmp/jsonfile.json)"

2. 在bash中先读取并转义JSON,再传入here-doc

如果坚持用here-doc,先把JSON内容读入bash变量,同时转义单引号(避免SQL语法错误),再传递给psql:

#!/bin/bash
# 读取JSON并转义单引号(把'替换成'',符合PostgreSQL的字符串转义规则)
json_content=$(sed "s/'/''/g" /tmp/jsonfile.json)

psql -X -h localhost -U <dbuser> -d <dbname> <<EOF
CREATE TABLE IF NOT EXISTS cardtable(id SERIAL PRIMARY KEY, charcolumn VARCHAR(20) NOT NULL, cardcolumn JSON NOT NULL);
INSERT INTO cardtable(charcolumn, cardcolumn) VALUES ('USA', '$json_content');
EOF

3. 让psql直接读取文件内容(跳过bash命令替换)

你也可以用psql的内部命令读取文件,比如用\set结合psql的命令替换,关键是用单引号包裹让bash不提前处理:

#!/bin/bash
psql -X -h localhost -U <dbuser> -d <dbname> <<EOF
CREATE TABLE IF NOT EXISTS cardtable(id SERIAL PRIMARY KEY, charcolumn VARCHAR(20) NOT NULL, cardcolumn JSON NOT NULL);
\set var '\`cat /tmp/jsonfile.json\`'
INSERT INTO cardtable(charcolumn, cardcolumn) VALUES ('USA', :'var');
EOF

内容的提问来源于stack exchange,提问作者RoT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:16:24