Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash Jq直接替换文件中的文本(如sed-i)_Bash_Jq - Fatal编程技术网

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

Bash Jq直接替换文件中的文本(如sed-i),bash,jq,Bash,Jq,我有一个json文件,需要在特定条件下更新 示例json { "Actions" : [ { "value" : "1", "properties" : { "name" : "abc", "age" : "2", "other ": "test1" } }, { "value" : "2",

我有一个json文件,需要在特定条件下更新

示例json

{
   "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
另一种方法是使用
海绵
实用程序(GNU
moreutils
的一部分):

第三个选项可能很有用,如果它有利于避免在没有更改的情况下更新文件。下面是一个脚本,演示了此功能:

#!/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