使用 jq 修改 JSON
Modifying JSON by using jq
我想使用 Linux 命令行修改 JSON 文件。
我尝试了这些步骤:
[root@localhost]# INPUT="dsa"
[root@localhost]# echo $INPUT
dsa
[root@localhost]# CONF_FILE=test.json
[root@localhost]# echo $CONF_FILE
test.json
[root@localhost]# cat $CONF_FILE
{
"global" : {
"name" : "asd",
"id" : 1
}
}
[root@localhost]# jq -r '.global.name |= '""$INPUT"" $CONF_FILE > tmp.$$.json && mv tmp.$$.json $CONF_FILE
jq: error: dsa/0 is not defined at <top-level>, line 1:
.global.name |= dsa
jq: 1 compile error
期望的输出:
[root@localhost]# cat $CONF_FILE
{ "global" : {
"name" : "dsa",
"id" : 1 } }
将 jq
与直接过滤器一起使用,应该为您完成。
.global.name = "dsa"
即
jq '.global.name = "dsa"' json-file
{
"global": {
"name": "dsa",
"id": 1
}
}
您可以使用 json 过滤器,here。
您唯一的问题是传递给 jq
的脚本引用不正确。
在您的特定情况下,使用带有嵌入式 \
-转义 "
实例的单个双引号字符串可能是最简单的:
jq -r ".global.name = \"$INPUT\"" "$CONF_FILE" > tmp.$$.json && mv tmp.$$.json "$CONF_FILE"
但是,一般来说, 显示了一种比直接在脚本中嵌入 shell 变量引用更可靠的替代方法 :使用 --arg
选项 将值作为 jq
变量 允许 单引号 脚本,这是更可取的,因为它避免了混淆 shell 预先扩展了哪些元素,并且避免了转义应该传递给 jq
.[=38 的 $
实例的需要=]
还有:
- 只需
=
即可赋值;虽然 |=
,即所谓的更新运算符,也可以工作,但在这种情况下它的行为与 =
相同,因为 RHS 是 文字 ,而不是引用 LHS 的表达式 - 参见 the manual.
- 您应该经常用双引号引用您的 shell 变量引用,并且您应该避免使用全部大写的变量名称以便 avoid conflicts with environment variables and special shell variables.
至于为什么你的引用不起作用:
'.global.name |= '""$INPUT""
由以下标记组成:
- 字符串文字
.global.name |=
(由于单引号)
- 字符串文字
""
- 即空字符串 - 在 jq
看到脚本之前,shell 会 删除 引号
- 对变量
$INPUT
的 未引用 引用(这使得它的值受到分词和通配的影响)。
- 文字的另一个实例
""
。
根据您的示例值,jq
最终看到以下字符串作为其脚本:
.global.name |= dsa
如您所见,缺少双引号,导致 jq
将 dsa
解释为 函数名称 而不是字符串文字,并且由于没有参数传递给(不存在的)函数 dsa
,jq
的错误消息将其引用为 dsa/0
- 一个没有(0
)参数的函数。
使用--arg
选项传递值更简单和安全:
jq -r --arg newname "$INPUT" '.global.name |= $newname' "$CONF_FILE"
这确保 $INPUT
的准确值被使用并引用为 JSON 值。
我想使用 Linux 命令行修改 JSON 文件。
我尝试了这些步骤:
[root@localhost]# INPUT="dsa"
[root@localhost]# echo $INPUT
dsa
[root@localhost]# CONF_FILE=test.json
[root@localhost]# echo $CONF_FILE
test.json
[root@localhost]# cat $CONF_FILE
{
"global" : {
"name" : "asd",
"id" : 1
}
}
[root@localhost]# jq -r '.global.name |= '""$INPUT"" $CONF_FILE > tmp.$$.json && mv tmp.$$.json $CONF_FILE
jq: error: dsa/0 is not defined at <top-level>, line 1:
.global.name |= dsa
jq: 1 compile error
期望的输出:
[root@localhost]# cat $CONF_FILE
{ "global" : {
"name" : "dsa",
"id" : 1 } }
将 jq
与直接过滤器一起使用,应该为您完成。
.global.name = "dsa"
即
jq '.global.name = "dsa"' json-file
{
"global": {
"name": "dsa",
"id": 1
}
}
您可以使用 json 过滤器,here。
您唯一的问题是传递给 jq
的脚本引用不正确。
在您的特定情况下,使用带有嵌入式 \
-转义 "
实例的单个双引号字符串可能是最简单的:
jq -r ".global.name = \"$INPUT\"" "$CONF_FILE" > tmp.$$.json && mv tmp.$$.json "$CONF_FILE"
但是,一般来说,--arg
选项 将值作为 jq
变量 允许 单引号 脚本,这是更可取的,因为它避免了混淆 shell 预先扩展了哪些元素,并且避免了转义应该传递给 jq
.[=38 的 $
实例的需要=]
还有:
- 只需
=
即可赋值;虽然|=
,即所谓的更新运算符,也可以工作,但在这种情况下它的行为与=
相同,因为 RHS 是 文字 ,而不是引用 LHS 的表达式 - 参见 the manual. - 您应该经常用双引号引用您的 shell 变量引用,并且您应该避免使用全部大写的变量名称以便 avoid conflicts with environment variables and special shell variables.
至于为什么你的引用不起作用:
'.global.name |= '""$INPUT""
由以下标记组成:
- 字符串文字
.global.name |=
(由于单引号) - 字符串文字
""
- 即空字符串 - 在jq
看到脚本之前,shell 会 删除 引号 - 对变量
$INPUT
的 未引用 引用(这使得它的值受到分词和通配的影响)。 - 文字的另一个实例
""
。
根据您的示例值,jq
最终看到以下字符串作为其脚本:
.global.name |= dsa
如您所见,缺少双引号,导致 jq
将 dsa
解释为 函数名称 而不是字符串文字,并且由于没有参数传递给(不存在的)函数 dsa
,jq
的错误消息将其引用为 dsa/0
- 一个没有(0
)参数的函数。
使用--arg
选项传递值更简单和安全:
jq -r --arg newname "$INPUT" '.global.name |= $newname' "$CONF_FILE"
这确保 $INPUT
的准确值被使用并引用为 JSON 值。