简体   繁体   中英

json value replace using sed

I have a .json file where I need to replace a particular value:

{
    "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"
        }
    ]
}

Particularly, I need to replace the partition_size_nominal tag of the root partition

The best way I could come up with is very 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

The basic idea is: find root label tag, search backward for beginning of block, search forward for end of block, replace the partition size tag value within block. I can't assume that the partition size tag is after the label tag, hence searching for the block bounds.

Does anyone know of a more elegant solution for this type of situation?

As mentioned, jq is the way to go when working with JSON in a shell script. This:

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

outputs

{
  "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"
    }
  ]
}

(Assuming the variables set in your shell script)

Minor changes in whitespace aside, you can use jq for this:

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

It looks a little intimidating, but it's not too complicated. jq operates using filters ; every filter takes an input, does something, and produces an output.

The top-level operator in this expression, |= , combines its left-hand and right-hand operands into a new filter which takes the incoming JSON object as input.

  • The left-hand side selects the element you want to change, namely the partition_size_nominal element of the object whose label element has the value "root" .
  • The right-hand side is the new value for this element.

The output of |= is then the original object, with the output of the left-hand operand as the target to which the value of the right-hand operand is assigned..

--arg t "$tag" binds the result of JSON-encoding "$tag" to the variable named t .

--argjson v "$newvalue" assumes that "$newvalue" is already properly encoded as a JSON value, and binds it to the variable named v .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM