web-dev-qa-db-ja.com

ファイル上のテキストを直接置き換えるJq(sed -iなど)

特定の条件で更新する必要がある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"'

出力(端末に出力)

{
  "value": "1",
  "properties": {
    "name": "abc",
    "age": "2",
    "other ": "test1"
  }
}
{
  "value": "2",
  "properties": {
    "name": "def",
    "age": "3",
    "other": "no-test"
  }
}

このコマンドは必要な変更を加えますが、json全体を端末に出力し、ファイル自体には変更を加えません。

Jqにファイルを直接変更させるオプションがあるかどうかをアドバイスしてください(sed -iと同様)。

23
Supra

この投稿は、sedの「-i」オプションに相当するものが存在しないこと、特に以下の状況に関する質問に対処します。

たくさんのファイルがあり、それぞれを別々のファイルに書き込むのは簡単ではありません。

少なくともMacまたはLinuxまたは同様の環境で作業している場合、いくつかのオプションがあります。彼らの長所と短所は http://backreference.org/2011/01/29/in-place-editing-of-files/ で議論されているので、3つのテクニックに焦点を当てます。

1つは、次の行に沿って単に「&&」を使用することです。

jq ... INPUT > INPUT.tmp && mv INPUT.tmp INPUT

もう1つは、spongeユーティリティ(GNU moreutils)の一部)を使用することです。

jq ... INPUT | sponge INPUT

3番目のオプションは、ファイルに変更がない場合にファイルの更新を避けることが有利な場合に役立ちます。このような機能を説明するスクリプトを次に示します。

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

コンテキストを変更せずにアクションオブジェクトを更新する必要があります。そこにパイプを置くことで、個々のアクションごとにコンテキストを変更しています。いくつかの括弧でそれを制御できます。

$ 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のようにファイルに対してインプレース更新を行いません。

5
Jeff Mercado

重複した質問に対する回答を使用

割り当ては、実行された割り当てでオブジェクト全体を出力するため、変更された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"]

上記は、.Actionsが編集されたjson全体を出力します。 jqにはsed -iのような機能はありませんでしたが、必要なことは、それを sponge にパイプで戻して| spongeを持つファイルに戻すことだけです

 jq '.Actions=([.Actions[] | if .properties.age == "3" then .properties.other = "no-test" else . end])' sample.json | sponge sample.json
0
Will Barnwell