使用 jq 就地修改 json 中的键值
Posted
技术标签:
【中文标题】使用 jq 就地修改 json 中的键值【英文标题】:Modify a key-value in a json using jq in-place 【发布时间】:2017-07-31 16:49:11 【问题描述】:我有一个 json,我想在其中修改一个特定的值,但终端总是显示带有修改后的值的 json,但它实际上并没有改变特定文件中的值。示例 json:
name: 'abcd',
age: 30,
address: 'abc'
我想更改文件本身的地址值,但到目前为止我一直无法这样做。我尝试使用:
jq '.address = "abcde"' test.json
但它没有用。有什么建议吗?
【问题讨论】:
这能回答你的问题吗? Jq to replace text directly on file (like sed -i) 【参考方案1】:使用临时文件;这就是任何声称可以进行就地编辑的程序正在做的事情。
tmp=$(mktemp)
jq '.address = "abcde"' test.json > "$tmp" && mv "$tmp" test.json
如果地址不是硬编码的,则通过 jq
参数传递正确的地址:
address=abcde
jq --arg a "$address" '.address = $a' test.json > "$tmp" && mv "$tmp" test.json
【讨论】:
这适用于硬编码字符串。变量是否有任何解决方案,即 $address @ahmed_khan_89 你可以使用 jq '.address = "'$address'"' 不,不要将字符串插入jq
过滤器。请改用jq --arg a "$address" '.address = $a'
。
@chepner 你怎么不推荐插入字符串?当我使用 Pujan 的方法时它可以工作
@AlexanderD 因为插值不一定将参数传递给您的过滤器;它构建一个过滤器,该过滤器取决于如何解析变量扩展。【参考方案2】:
AFAIK jq
不支持就地编辑,因此您必须先重定向到一个临时文件,然后用它替换您的原始文件,或者使用 moreutils 包中的 sponge
实用程序,如下所示:
jq '.address = "abcde"' test.json|sponge test.json
还有其他技术可以“重定向到同一个文件”,例如将输出保存在变量 e.t.c 中。如果您想了解更多相关信息,“Unix 和 Linux StackExchange”是一个很好的起点。
【讨论】:
不幸的是,CentOS 8 atm 上没有更多实用程序/海绵.. 没有sponge
: echo "$( jq '.address = "abcde"' test.json )" > test.json
小心!将文件名作为参数传递给sponge
,如答案所示。这是错误的:jq . test.json | sponge > test.json
,你必须这样做jq . test.json | sponge test.json
另外点头让我看看海绵(1)
不要重定向到@codekandis 评论所建议的相同文件。这并不总是有效。大文件会导致问题,包括空格、不可打印和转义序列。永远不要将文件重定向到自身,这总是一个坏主意。查看海绵或使用临时文件,除非您了解正在发生的事情,否则不要尝试以不同的方式进行操作。【参考方案3】:
临时文件在不需要时会增加更多复杂性(除非您真正处理的 JSON 文件太大而无法将它们放入内存(GB 到 100 的 GB 或 TB,具体取决于您拥有多少 RAM/并行度)
纯粹的 bash 方式。
contents="$(jq '.address = "abcde"' test.json)" && \
echo "$contents" > test.json
优点
没有临时文件可以处理 纯 bash 不需要管理员安装sponge
,默认不安装
更简单
注意:这不能组合为“一个命令”,因为重定向在运行表达式的左侧 (LHS) 之前 开始,并且在运行 jq
之前开始重定向会错误地清空文件,因此有两个单独的命令。
【讨论】:
这个答案对于诸如在你的 package.json 上修改版本(例如contents="$(jq '.version = "$version"' package.json)" && echo "$contents" > package.json
)等事情特别有用【参考方案4】:
只是为了添加到 chepner 答案中,如果你想在 shell 脚本中使用它。
test.json
"name": "abcd",
"age": 30,
"address": "abc"
脚本.sh
#!/bin/bash
address="abcde"
age=40
# Strings:
jq --arg a "$address" '.address = $a' test.json > "tmp" && mv "tmp" test.json
# Integers:
jq --argjson a "$age" '.age = $a' test.json > "tmp" && mv "tmp" test.json
【讨论】:
【参考方案5】:具有更改单个值和多个值的嵌套 json 示例。
config.json
"Parameters":
"Environment": "Prod",
"InstanceType": "t2.micro",
"AMIID": "ami-02d8e11",
"ConfigRegion": "eu-west-1"
使用以下命令,您可以编辑多个值。
tmp=$(mktemp)
jq '.Parameters.AMIID = "ami-02d8sdfsdf" | .Parameters.Environment = "QA"' config.json > "$tmp" && mv "$tmp" config.json
使用以下命令,您可以编辑单个值。
tmp=$(mktemp)
jq '.Parameters.AMIID = "ami-02d8sdfsdf"' config.json > "$tmp" && mv "$tmp" config.json
【讨论】:
【参考方案6】:这应该可以工作
address = aaaaa
echo $(jq --arg a "$address" '.address = ($a)' test.json) > test.json
无论出于何种原因,如果没有回显,它会生成一个 bin 文件,而我的 python 脚本无法解析它。
【讨论】:
在 shell 脚本中将结果流式传输到输入文件通常是有风险的:>
通常会导致在执行其余命令之前截断输出文件。可能子shell 命令$(...)
将其推迟到执行shell 脚本之后。一般来说,我总是使用命令行选项来处理这种特殊情况,或者缺少这种情况,写入中间文件。【参考方案7】:
我不喜欢任何解决方案并创建了sde
utility。
pip install sde
那么你可以简单地做:
sde address abcde test.json
【讨论】:
以上是关于使用 jq 就地修改 json 中的键值的主要内容,如果未能解决你的问题,请参考以下文章