【问题标题】:json value replace using sed使用 sed 替换 json 值
【发布时间】:2020-07-01 16:27:51
【问题描述】:

我有一个需要替换特定值的 .json 文件:

{
    "partitions": [
        {
            "filesystem_type": "FAT",
            "label": "boot",
            "mkfs_options": "-F 32",
            "partition_size_nominal": 256,
            "uncompressed_tarball_size": 53,
            "want_maximised": false,
            "sha256sum": "dd54710df7756e64cff43bba3c930e85c97f22d43e0d32bc37396be34166c148"
        },
        {
            "filesystem_type": "ext4",
            "label": "root",
            "mkfs_options": "-O ^huge_file",
            "partition_size_nominal": 1415,
            "uncompressed_tarball_size": 1015,
            "want_maximised": true,
            "sha256sum": "bb0892d4a028ae9d282849d05adf851fe54173013f6331e74a4bdd07e4af8dab"
        }
    ]
}

特别需要替换root分区的partition_size_nominal标签

我能想出的最好方法是非常hacky:

#!/bin/bash
fname=partitions.json
tag=partition_size_nominal
newvalue=2942
rootline=$(sed -n '/label.*root/=' $fname | head -1)
blockstart=$(sed -n '1,'"$rootline"'p' $fname | tac | sed -n '/{/=' | head -1)
blockstart=$(( rootline - blockstart + 1 ))
blockend=$(sed -n ''"$blockstart"',$p' $fname | sed -n '/}/=' | head -1)
blockend=$(( blockstart + blockend -1 ))
sed ''"$blockstart"','"$blockend"'s/"'"$tag"'".*/"'"$tag"'": '"$newvalue"',/' $fname

基本思路是:找到根标签标签,向后搜索块开始,向前搜索块结束,替换块内的分区大小标签值。我不能假设分区大小标签在标签标签之后,因此搜索块边界。

有没有人知道针对这种情况的更优雅的解决方案?

【问题讨论】:

  • jq 是一个理解 json 的 cli 工具,在这里比 sed 更容易使用
  • 谢谢,我会调查的
  • 这能回答你的问题吗? Parsing JSON with Unix tools

标签: json bash sed


【解决方案1】:

除了空白的细微变化,您可以使用jq

fname=partitions.json
tag=partition_size_nominal
newvalue=2942
jq --arg t "$tag" --argjson v "$newvalue" \ 
  '(.partitions[] | select(.label == "root"))[$t] |= $v' "$fname"

它看起来有点吓人,但并不太复杂。 jq 使用过滤器进行操作;每个过滤器都接受一个输入,做一些事情,然后产生一个输出。

此表达式中的顶级运算符 |= 将其左手操作数和右手操作数组合成一个新过滤器,该过滤器将传入的 JSON 对象作为输入。

  • 左侧选择要更改的元素,即label元素值为"root"的对象的partition_size_nominal元素。
  • 右侧是该元素的新值。

|= 的输出是原始对象,左侧操作数的输出作为分配右侧操作数值的目标。

--arg t "$tag" 将 JSON 编码的结果 "$tag" 绑定到名为 t 的变量。

--argjson v "$newvalue" 假定 "$newvalue" 已正确编码为 JSON 值,并将其绑定到名为 v 的变量。

【讨论】:

    【解决方案2】:

    如前所述,jq 是在 shell 脚本中使用 JSON 时要走的路。这个:

    jq --arg size "$newvalue" '
      .partitions |= [.[] | if .label == "root" then
                              .partition_size_nominal |= ($size | tonumber)
                            else
                              .
                            end]' "$fname"
    

    输出

    {
      "partitions": [
        {
          "filesystem_type": "FAT",
          "label": "boot",
          "mkfs_options": "-F 32",
          "partition_size_nominal": 256,
          "uncompressed_tarball_size": 53,
          "want_maximised": false,
          "sha256sum": "dd54710df7756e64cff43bba3c930e85c97f22d43e0d32bc37396be34166c148"
        },
        {
          "filesystem_type": "ext4",
          "label": "root",
          "mkfs_options": "-O ^huge_file",
          "partition_size_nominal": 2942,
          "uncompressed_tarball_size": 1015,
          "want_maximised": true,
          "sha256sum": "bb0892d4a028ae9d282849d05adf851fe54173013f6331e74a4bdd07e4af8dab"
        }
      ]
    }
    

    (假设您的 shell 脚本中设置了变量)

    【讨论】:

      猜你喜欢
      • 2017-08-07
      • 1970-01-01
      • 2018-01-09
      • 2020-03-07
      • 1970-01-01
      • 1970-01-01
      • 2014-12-04
      • 2017-01-07
      • 1970-01-01
      相关资源
      最近更新 更多