使用jq修改json中的键值

wol*_*ane 35 bash shell json jq

我有一个json,我想在其中修改一个特定的值,但终端始终显示带有修改值的json,但它实际上并没有更改特定文件中的值.示例json:

{
   name: 'abcd',
   age: 30,
   address: 'abc'
}
Run Code Online (Sandbox Code Playgroud)

我想更改文件本身的地址值,但到目前为止我一直无法这样做.我试过用:

jq '.address = "abcde"' test.json
Run Code Online (Sandbox Code Playgroud)

但它不起作用.有什么建议?

che*_*ner 58

使用临时文件; 这是任何声称进行就地编辑的程序正在做的事情.

tmp=$(mktemp)
jq '.address = "abcde"' test.json > "$tmp" && mv "$tmp" test.json
Run Code Online (Sandbox Code Playgroud)

  • 不,不要将字符串插入到“jq”过滤器中。请改用 `jq --arg a "$address" '.address = $a'`。 (10认同)
  • @chepner 为什么你不建议插入字符串?当我使用 Pujan 的方法时它有效 (3认同)
  • @AlexanderD因为插值不一定将参数传递给您的过滤器;它“构建”一个过滤器,该过滤器取决于如何解析变量扩展。 (3认同)
  • `mv` 是原子的;‘猫’不是。您可以在执行“mv”之前调整临时文件的权限和所有者,但在“cat”覆盖其内容时阻止另一个进程访问“test.json”则更加困难。 (2认同)
  • 另一个常见的临时文件名是添加一个波形符,如“test.json~”,或在前面添加一个点和其他内容,如“.jq.test.json”,将文件保留在同一目录中。这样,移动操作就不会潜在地跨文件系统,从而导致非原子复制和删除操作。加: mktemp 设置自己的权限。可能需要,但可能不需要 (2认同)

zep*_*lin 42

AFAIK jq不支持就地编辑,因此您必须先重定向到临时文件,然后用它替换原始文件,或者使用spongemoreutils包中的实用程序,如下所示:

jq '.address = "abcde"' test.json|sponge test.json
Run Code Online (Sandbox Code Playgroud)

还有其他技术可以"重定向到同一个文件",比如将输出保存在变量等中"Unix&Linux StackExchange"是一个很好的起点,如果你想了解更多.

  • 没有 `sponge`: `echo "$( jq '.address = "abcde"' test.json )" > test.json` (9认同)
  • 不要重定向到 @codekandis 评论建议的同一文件。这并不总是有效。大文件会导致问题,还有空格、不可打印和逃逸序列。切勿将文件重定向到其自身,这始终是一个坏主意。请参阅海绵或使用临时文件,除非您了解发生了什么,否则不要尝试以不同的方式进行操作。 (3认同)
  • 当心!将文件名作为参数传递给“sponge”,如答案所示。这是错误的:`jq 。测试.json | Sponge > test.json` ,您必须执行 `jq 。测试.json | 海绵测试.json` (2认同)

And*_*ndy 29

临时文件在不需要时会增加更多的复杂性(除非您真正处理 JSON 文件太大以至于无法将它们放入内存中(GB 到 100 的 GB 或 TB,取决于您拥有多少 RAM/并行度)

纯粹的 bash 方式。

contents="$(jq '.address = "abcde"' test.json)" && \
echo "${contents}" > test.json
Run Code Online (Sandbox Code Playgroud)

优点

  • 没有临时文件可以处理
  • 纯粹的 bash
  • 不需要管理员安装sponge,默认不安装
  • 更简单

注意:这不能组合为“一个命令”,因为重定向表达式的左侧 (LHS) 运行之前开始,并且在运行之前启动重定向会jq错误地清空文件,因此是两个单独的命令。

  • 这个答案对于诸如修改 package.json 上的版本之类的事情特别有用(例如 `contents="$(jq '.version = "$version"' package.json)" && echo "${contents}" > package .json`) (2认同)
  • @Pieter你不应该这样做。它非常不可靠,一旦环境发生变化(文件大小、格式化文件系统、CPU 使用率、月相)就会失败。一旦 RHS 上的重定向打开并清除“test.json”文件,运行的“jq”就会读取最有可能丢失的文件内容。它似乎有效,但这并不安全。 (2认同)

mah*_*hod 8

具有更改单个值和多个值的嵌套 json 的示例。

配置.json

{
  "Parameters": {
    "Environment": "Prod",
    "InstanceType": "t2.micro",
    "AMIID": "ami-02d8e11",
    "ConfigRegion": "eu-west-1"
  }
}
Run Code Online (Sandbox Code Playgroud)

使用以下命令,您可以编辑多个值。

tmp=$(mktemp)
jq '.Parameters.AMIID = "ami-02d8sdfsdf" | .Parameters.Environment = "QA"' config.json > "$tmp" && mv "$tmp" config.json
Run Code Online (Sandbox Code Playgroud)

使用以下命令,您可以编辑单个值。

tmp=$(mktemp)
jq '.Parameters.AMIID = "ami-02d8sdfsdf"' config.json > "$tmp" && mv "$tmp" config.json
Run Code Online (Sandbox Code Playgroud)


小智 7

只是为了添加到 chepner 答案,如果你想在 shell 脚本中使用它。

测试文件

{
  "name": "abcd",
  "age": 30,
  "address": "abc"
}
Run Code Online (Sandbox Code Playgroud)

脚本文件

#!/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
Run Code Online (Sandbox Code Playgroud)


小智 7

这应该有效

address = aaaaa
echo $(jq --arg a "$address" '.address = ($a)' test.json) > test.json
Run Code Online (Sandbox Code Playgroud)

不管出于什么原因,如果没有 echo,它会生成一个 bin 文件,而我的 python 脚本无法解析它。