bash Jq 直接替换文件上的文本(如 sed -i)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36565295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Jq to replace text directly on file (like sed -i)
提问by Supra
I have a json file that needs to be updated on a certain condition.
我有一个需要在特定条件下更新的 json 文件。
Sample json
示例 json
{
"Actions" : [
{
"value" : "1",
"properties" : {
"name" : "abc",
"age" : "2",
"other ": "test1"
}
},
{
"value" : "2",
"properties" : {
"name" : "def",
"age" : "3",
"other" : "test2"
}
}
]
}
I am writing a script that makes use of Jq to match a value and update, as shown below
我正在编写一个脚本,它利用 Jq 来匹配值和更新,如下所示
cat sample.json | jq '.Actions[] | select (.properties.age == "3") .properties.other = "no-test"'
Output (printed to terminal)
输出(打印到终端)
{
"value": "1",
"properties": {
"name": "abc",
"age": "2",
"other ": "test1"
}
}
{
"value": "2",
"properties": {
"name": "def",
"age": "3",
"other": "no-test"
}
}
While this command makes the needed change, it outputs the entire json on the terminal and does not make change to the file itself.
虽然此命令进行了所需的更改,但它会在终端上输出整个 json,并且不会更改文件本身。
Please advise if there is an option to have jq make changes on the file directly (similar to sed -i).
请告知是否可以选择让 jq 直接对文件进行更改(类似于 sed -i)。
回答by peak
This post addresses the question about the absence of the equivalent of sed's "-i" option, and in particular the situation described:
这篇文章解决了缺少 sed 的“-i”选项等价物的问题,特别是描述的情况:
I have a bunch of files and writing each one to a separate file wouldn't be easy.
我有一堆文件,将每个文件写入一个单独的文件并不容易。
There are several options, at least if you are working in a Mac or Linux or similar environment. Their pros and cons are discussed at http://backreference.org/2011/01/29/in-place-editing-of-files/so I'll focus on just three techniques:
有多种选择,至少如果您在 Mac 或 Linux 或类似环境中工作。它们的优缺点在http://backreference.org/2011/01/29/in-place-editing-of-files/中讨论, 所以我将只关注三种技术:
One is simply to use "&&" along the lines of:
一种是简单地使用“&&”,如下所示:
jq ... INPUT > INPUT.tmp && mv INPUT.tmp INPUT
Another is to use the sponge
utility (part of GNU moreutils
):
另一个是使用该sponge
实用程序(GNU 的一部分moreutils
):
jq ... INPUT | sponge INPUT
The third option might be useful if it is advantageous to avoid updating a file if there are no changes to it. Here is a script which illustrates such a function:
如果有利于避免在没有更改的情况下更新文件,则第三个选项可能很有用。这是一个说明此类功能的脚本:
#!/bin/bash
function maybeupdate {
local f=""
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
回答by Jeff Mercado
You'll want to update the action objects without changing the context. By having the pipe there, you're changing the context to each individual action. You can control that with some parentheses.
您将希望在不更改上下文的情况下更新操作对象。通过在那里放置管道,您可以更改每个单独操作的上下文。你可以用一些括号来控制它。
$ jq --arg age "3" \
'(.Actions[] | select(.properties.age == $age).properties.other) = "no-test"' sample.json
This should yield:
这应该产生:
{
"Actions": [
{
"value": "1",
"properties": {
"name": "abc",
"age": "2",
"other ": "test1"
}
},
{
"value": "2",
"properties": {
"name": "def",
"age": "3",
"other": "no-test"
}
}
]
}
You can redirect the results to a file to replace the input file. It won't do in-place updates to a file as sed does.
您可以将结果重定向到文件以替换输入文件。它不会像 sed 那样对文件进行就地更新。
回答by moriaki
instead of sponge
:
而不是sponge
:
cat <<< $(jq 'QUERY' sample.json) > sample.json
回答by Charles Merriam
You ran into two issues:
你遇到了两个问题:
- This is a common problem for text processing, not solved in the base Linux distribution.
- jqdid not write special code to overcome this problem.
- 这是文本处理的常见问题,在基本 Linux 发行版中没有解决。
- jq没有写特殊的代码来克服这个问题。
One good solution:
一个很好的解决方案:
- Install moreutilsusing
brew install moreutils
or your favorite package manager. This contains the handy programsponge
, for just this purpose. - Use
cat myfile | jq blahblahblah | sponge myfile
. That is, run jq, capturing the standard out, when jqhas finished, then write the standard output overmyfile
(the input file).
- 使用或您最喜欢的包管理器安装moreutils
brew install moreutils
。这包含方便的程序sponge
,仅用于此目的。 - 使用
cat myfile | jq blahblahblah | sponge myfile
. 也就是说,运行jq,捕获标准输出,当jq完成后,然后将标准输出myfile
(输入文件)写入。
回答by Will Barnwell
Using my answer to a duplicate question
Assignment prints the whole object with the assignment executed so you could assign a new value to
.Actions
of the modified Actions array.Actions=([.Actions[] | if .properties.age == "3" then .properties.other = "no-test" else . end])
I used an if statement but we can use your code to do the same thing
.Actions=[.Actions[] | select (.properties.age == "3").properties.other = "no-test"]
赋值打印执行赋值的整个对象,以便您可以
.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"]
The above will output the entire json with .Actions
edited.
jq does not had sed -i
like functionality, but all you need to do is pipe it back into a spongeto the file with | sponge
以上将输出整个 json 并.Actions
编辑。jq 没有sed -i
类似的功能,但您需要做的就是将它用管道送回海绵文件中| sponge
jq '.Actions=([.Actions[] | if .properties.age == "3" then .properties.other = "no-test" else . end])' sample.json | sponge sample.json