webentwicklung-frage-antwort-db.com.de

Jq, um den Text direkt in der Datei zu ersetzen

Ich habe eine Json-Datei, die unter bestimmten Bedingungen aktualisiert werden muss. 

Probe Json

{
   "Actions" : [
      {
         "value" : "1",
         "properties" : {
            "name" : "abc",
            "age" : "2",
            "other ": "test1"
          }
      },
      {
         "value" : "2",
         "properties" : {
            "name" : "def",
            "age" : "3",
            "other" : "test2"
          }
      }
   ]
}

Ich schreibe ein Skript, das Jq verwendet, um einen Wert abzugleichen und zu aktualisieren, wie unten gezeigt

cat sample.json |  jq '.Actions[] | select (.properties.age == "3") .properties.other = "no-test"'

Ausgabe (auf Terminal gedruckt)

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

Während dieser Befehl die erforderliche Änderung vornimmt, gibt er den gesamten Json-Code auf dem Terminal aus und nimmt keine Änderungen an der Datei selbst vor. 

Bitte geben Sie an, ob es eine Option gibt, mit der jq Änderungen direkt an der Datei vornehmen kann (ähnlich wie bei sed -i).

16
Supra

Dieser Beitrag befasst sich mit der Frage nach dem Fehlen des Äquivalents der Option "-i" von sed und insbesondere der beschriebenen Situation:

Ich habe eine Reihe von Dateien und es wäre nicht einfach, jede in eine separate Datei zu schreiben. 

Es gibt mehrere Optionen, zumindest wenn Sie in einer Mac- oder Linux- oder ähnlichen Umgebung arbeiten. Ihre Vor- und Nachteile werden unter http://de.backup.org/2011/01/29/in-place-editing-of-files .__ diskutiert :

Eine ist einfach "&&" zu verwenden:

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

Ein anderes ist die Verwendung des Dienstprogramms sponge (Teil von GNU moreutils):

jq ... INPUT | sponge INPUT

Die dritte Option kann nützlich sein, wenn es vorteilhaft ist, das Aktualisieren einer Datei zu vermeiden, wenn sie nicht geändert wird. Hier ist ein Skript, das eine solche Funktion veranschaulicht:

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

Sie möchten die Aktionsobjekte aktualisieren, ohne den Kontext zu ändern. Wenn Sie die Pipe dort haben, ändern Sie den Kontext für jede einzelne Aktion. Sie können das mit einigen Klammern kontrollieren.

$ jq --arg age "3" \
'(.Actions[] | select(.properties.age == $age).properties.other) = "no-test"' sample.json

Dies sollte ergeben:

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

Sie können die Ergebnisse in eine Datei umleiten, um die Eingabedatei zu ersetzen. Es werden keine direkten Updates für eine Datei vorgenommen, wie dies bei sed der Fall ist.

5
Jeff Mercado

Meine Antwort auf eine doppelte Frage verwenden

Bei der Zuweisung wird das gesamte Objekt mit der ausgeführten Zuweisung gedruckt, sodass Sie .Actions des geänderten Actions-Arrays einen neuen Wert zuweisen können

.Actions=([.Actions[] | if .properties.age == "3" then .properties.other = "no-test" else . end])

Ich habe eine if-Anweisung verwendet, aber wir können Ihren Code verwenden, um dasselbe zu tun

.Actions=[.Actions[] | select (.properties.age == "3").properties.other = "no-test"]

Das obige wird den gesamten Json mit .Actions bearbeitet. Ausgeben Jq hat keine sed -i-artige Funktionalität, aber alles, was Sie tun müssen, ist, es in einen sponge zurück in die Datei mit | sponge zu leiten.

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