Bash Jq直接替换文件中的文本(如sed-i)
我有一个json文件,需要在特定条件下更新 示例jsonBash Jq直接替换文件中的文本(如sed-i),bash,jq,Bash,Jq,我有一个json文件,需要在特定条件下更新 示例json { "Actions" : [ { "value" : "1", "properties" : { "name" : "abc", "age" : "2", "other ": "test1" } }, { "value" : "2",
{
"Actions" : [
{
"value" : "1",
"properties" : {
"name" : "abc",
"age" : "2",
"other ": "test1"
}
},
{
"value" : "2",
"properties" : {
"name" : "def",
"age" : "3",
"other" : "test2"
}
}
]
}
我正在编写一个脚本,它使用Jq来匹配一个值并进行更新,如下所示
cat sample.json | jq '.Actions[] | select (.properties.age == "3") .properties.other = "no-test"'
输出(打印到终端)
虽然此命令进行了必要的更改,但它会在终端上输出整个json,而不会对文件本身进行更改
请告知是否有让jq直接对文件进行更改的选项(类似于sed-i)。您希望在不更改上下文的情况下更新操作对象。通过将管道放在那里,可以更改每个动作的上下文。你可以用括号来控制它
$ jq --arg age "3" \
'(.Actions[] | select(.properties.age == $age).properties.other) = "no-test"' sample.json
这将产生:
{
"Actions": [
{
"value": "1",
"properties": {
"name": "abc",
"age": "2",
"other ": "test1"
}
},
{
"value": "2",
"properties": {
"name": "def",
"age": "3",
"other": "no-test"
}
}
]
}
可以将结果重定向到文件以替换输入文件。它不会像sed那样对文件进行就地更新。这篇文章解决了缺少sed的“-i”选项的问题,特别是描述的情况: 我有一堆文件,将每个文件写入一个单独的文件并不容易 至少在Mac或Linux或类似环境中工作时,有几种选择。他们的优点和缺点将在会议上讨论 因此,我将重点介绍三种技术: 一种是简单地使用“&&”,大致如下:
jq ... INPUT > INPUT.tmp && mv INPUT.tmp INPUT
另一种方法是使用海绵
实用程序(GNUmoreutils
的一部分):
第三个选项可能很有用,如果它有利于避免在没有更改的情况下更新文件。下面是一个脚本,演示了此功能:
#!/bin/bash
function maybeupdate {
local f="$1"
cmp -s "$f" "$f.tmp"
if [ $? = 0 ] ; then
/bin/rm $f.tmp
else
/bin/mv "$f.tmp" "$f"
fi
}
for f
do
jq . "$f" > "$f.tmp"
maybeupdate "$f"
done
Assignment打印执行赋值的整个对象,以便您可以为修改的Actions数组的.Actions
分配新值
.Actions=([.Actions[] | if .properties.age == "3" then .properties.other = "no-test" else . end])
我使用了if语句,但我们可以使用您的代码来做同样的事情
.Actions=[.Actions[] | select (.properties.age == "3").properties.other = "no-test"]
上面将输出整个json,并编辑.Actions
。
jq没有类似于sed-i的功能,但您所需要做的就是将它通过管道返回到一个文件中
jq '.Actions=([.Actions[] | if .properties.age == "3" then .properties.other = "no-test" else . end])' sample.json | sponge sample.json
而不是
海绵
:
cat <<< $(jq 'QUERY' sample.json) > sample.json
cat您遇到了两个问题:
- 这是文本处理的常见问题,在基本Linux发行版中没有解决
- jq并没有编写特殊的代码来解决这个问题
一个好的解决方案:
- 使用
brew Install moreutils
或您喜爱的软件包管理器安装。这包含了一个方便的程序海绵
,用于此目的
- 使用
cat myfile | jq blahblahblah |海绵myfile
。也就是说,当jq完成时,运行jq,捕获标准输出,然后将标准输出写入myfile
(输入文件)
谢谢杰夫,这非常有帮助。您建议使用什么工具直接对文件进行有条件的json更改?我有一堆文件,将每个文件写入一个单独的文件并不容易。再次感谢。如果您需要在命令行中执行此操作,jq非常棒。你可以用它做很多事情。如果您需要使用更多控制进行更复杂的更新,我只需要编写一个脚本,使用您最喜欢的脚本/编程语言进行更新。按照“CMDFILE”或类似的方式将输出管道化为输入通常会遭到严重反对,例如,正如在中所解释的那样,有许多好的替代方案,因此请相应地调整您的响应。对于“如何就地更改文件“另请参见FWIW,此处打开了一个功能请求:cat
是否真的能够替换海绵
?这能保证一直有效吗?我在ubuntu 18.04和JQ1.5.1上都不行。运行命令后Sample.json为空。是的,这很好,但最好不要覆盖源文件。如果出现问题,并且标准输出没有显示任何内容,则它将为空。当您需要复制并修改到其他地方时,这非常好。这对我来说非常好,但是如何编写格式化的(漂亮的)json呢?这个命令只写了一行,在Ubuntu18.04上运行得很好——我的示例命令cat
jq '.Actions=([.Actions[] | if .properties.age == "3" then .properties.other = "no-test" else . end])' sample.json | sponge sample.json
cat <<< $(jq 'QUERY' sample.json) > sample.json