我想使用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 } }
答案 0 :(得分:4)
您唯一的问题是传递给jq
的脚本引用错误。
在您的特定情况下,使用带有嵌入式\
- 转义"
实例的单个双引号字符串可能最简单:
jq -r ".global.name = \"$INPUT\"" "$CONF_FILE" > tmp.$$.json && mv tmp.$$.json "$CONF_FILE"
但是,一般来说, chepner's helpful answer显示了一种更强大的替代方法,可直接在脚本中嵌入shell变量引用:使用 --arg
选项传递一个值作为jq
变量允许单引号脚本,这是首选,因为它避免了对shell扩展的元素的混淆前面并且不需要转义应该传递给$
的{{1}}个实例。
此外:
jq
即可分配值;而=
,即所谓的更新运算符,也适用于此实例中的|=
,因为RHS是文字,而不是引用LHS - 见the manual。至于为什么你的报价不起作用:
=
由以下令牌组成:
'.global.name |= '""$INPUT""
(由于单引号).global.name |=
- 即空字符串 - 在""
看到脚本之前,shell将删除引号 jq
的未加引号引用(使其值受到分词和通配)的影响。$INPUT
的另一个例子。使用您的示例值,""
最终看到以下字符串作为其脚本:
jq
正如您所看到的,双引号丢失,导致.global.name |= dsa
将jq
解释为函数名称而不是字符串文字,因为没有传递任何参数到(不存在的)函数dsa
,dsa
的错误消息将其称为jq
- 一个没有(dsa/0
)参数的函数。
答案 1 :(得分:4)
使用--arg
选项传递值会更简单,更安全:
jq -r --arg newname "$INPUT" '.global.name |= $newname' "$CONF_FILE"
这确保使用$INPUT
的确切值并引用为JSON值。
答案 2 :(得分:1)
将jq
与直接过滤器一起使用,应该为您完成。
.global.name = "dsa"
即
jq '.global.name = "dsa"' json-file
{
"global": {
"name": "dsa",
"id": 1
}
}
您可以使用json过滤器here。