特定の条件で更新する必要がある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と同様)。
この投稿は、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
コンテキストを変更せずにアクションオブジェクトを更新する必要があります。そこにパイプを置くことで、個々のアクションごとにコンテキストを変更しています。いくつかの括弧でそれを制御できます。
$ 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のようにファイルに対してインプレース更新を行いません。
割り当ては、実行された割り当てでオブジェクト全体を出力するため、変更された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