Jq直接替换文件上的文本(如sed -i)

Sup*_*pra 28 bash json edit in-place jq

我有一个需要在某种条件下更新的json文件.

示例json

{
   "Actions" : [
      {
         "value" : "1",
         "properties" : {
            "name" : "abc",
            "age" : "2",
            "other ": "test1"
          }
      },
      {
         "value" : "2",
         "properties" : {
            "name" : "def",
            "age" : "3",
            "other" : "test2"
          }
      }
   ]
}
Run Code Online (Sandbox Code Playgroud)

我正在编写一个脚本,它使用Jq匹配值和更新,如下所示

cat sample.json |  jq '.Actions[] | select (.properties.age == "3") .properties.other = "no-test"'
Run Code Online (Sandbox Code Playgroud)

输出(打印到终端)

{
  "value": "1",
  "properties": {
    "name": "abc",
    "age": "2",
    "other ": "test1"
  }
}
{
  "value": "2",
  "properties": {
    "name": "def",
    "age": "3",
    "other": "no-test"
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然此命令进行了所需的更改,但它会在终端上输出整个json,而不会对文件本身进行更改.

请告知是否有选项让jq直接对文件进行更改(类似于sed -i).

小智 29

而不是sponge

cat <<< $(jq 'QUERY' sample.json) > sample.json
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案在 jq 读取文件和 shell 同时截断文件之间存在竞争。即使它对您有用,也不能保证它始终有效。 (3认同)
  • 这对我在 ubuntu 18.04 和 jq 1.5.1 上不起作用。运行命令后 Sample.json 为空。 (2认同)

pea*_*eak 26

这篇文章解决了缺少相当于sed的"-i"选项的问题,特别是描述的情况:

我有一堆文件,并将每个文件写入一个单独的文件并不容易.

有几种选择,至少如果您在Mac或Linux或类似环境中工作.他们的优点和缺点在http://backreference.org/2011/01/29/in-place-editing-of-files/讨论, 所以我将只关注三种技巧:

一个是简单地使用"&&":

jq ... INPUT > INPUT.tmp && mv INPUT.tmp INPUT
Run Code Online (Sandbox Code Playgroud)

另一种是使用该sponge实用程序(GNU的一部分moreutils):

jq ... INPUT | sponge INPUT
Run Code Online (Sandbox Code Playgroud)

如果在没有更改文件的情况下避免更新文件是有利的,则第三个选项可能很有用.这是一个说明这样一个功能的脚本:

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


Sha*_*iri 15

我使用yq,对于高级用户,-i需要这个(就地更新),希望添加到jq

yq -iP '.Email.Port=3030' config.json -o json
Run Code Online (Sandbox Code Playgroud)
  • -i就地更新
  • -P漂亮的印刷品
  • -o输出应该是json

yq --version
yq (https://github.com/mikefarah/yq/) version 4.21.1
Run Code Online (Sandbox Code Playgroud)


Cha*_*iam 10

你遇到了两个问题:

  • 这是文本处理的常见问题,在基本 Linux 发行版中没有解决。
  • jq没有写特殊的代码来克服这个问题。

一个很好的解决方案:

  • 使用或您最喜欢的包管理器安装moreutilsbrew install moreutils。这包含方便的程序sponge,仅用于此目的。
  • 使用cat myfile | jq blahblahblah | sponge myfile. 也就是说,运行jq,捕获标准输出,当jq完成后,然后将标准输出myfile(输入文件)写入。


小智 7

使用 tee 命令

\n
\xe2\x9e\x9c cat config.json|jq '.Actions[] | select (.properties.age == "3") .properties.other = "no-test"'|tee config.json\n{\n  "value": "1",\n  "properties": {\n    "name": "abc",\n    "age": "2",\n    "other ": "test1"\n  }\n}\n{\n  "value": "2",\n  "properties": {\n    "name": "def",\n    "age": "3",\n    "other": "no-test"\n  }\n}\n\n\xe2\x9e\x9c cat config.json\n{\n  "value": "1",\n  "properties": {\n    "name": "abc",\n    "age": "2",\n    "other ": "test1"\n  }\n}\n{\n  "value": "2",\n  "properties": {\n    "name": "def",\n    "age": "3",\n    "other": "no-test"\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n


Jef*_*ado 6

您需要在不更改上下文的情况下更新操作对象.通过在那里使用管道,您可以将上下文更改为每个单独的操作.您可以使用一些括号来控制它.

$ jq --arg age "3" \
'(.Actions[] | select(.properties.age == $age).properties.other) = "no-test"' sample.json
Run Code Online (Sandbox Code Playgroud)

这应该产生:

{
  "Actions": [
    {
      "value": "1",
      "properties": {
        "name": "abc",
        "age": "2",
        "other ": "test1"
      }
    },
    {
      "value": "2",
      "properties": {
        "name": "def",
        "age": "3",
        "other": "no-test"
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

您可以将结果重定向到文件以替换输入文件.它不会像sed那样对文件进行就地更新.