2017-01-06 3 views
2

Ich möchte eine JSON-Datei mithilfe der Linux-Befehlszeile ändern.Ändern von JSON mithilfe von jq

habe ich versucht, diese Schritte:

[[email protected]]# INPUT="dsa" 
[[email protected]]# echo $INPUT 
dsa 
[[email protected]]# CONF_FILE=test.json 
[[email protected]]# echo $CONF_FILE 
test.json 
[[email protected]]# cat $CONF_FILE 
{ 
    "global" : { 
    "name" : "asd", 
    "id" : 1 
    } 
} 
[[email protected]]# jq -r '.global.name |= '""$INPUT"" $CONF_FILE > tmp.$$.json && mv tmp.$$.json $CONF_FILE 
jq: error: dsa/0 is not defined at <top-level>, line 1: 
.global.name |= dsa 
jq: 1 compile error 

gewünschte Ausgabe:

[[email protected]]# cat $CONF_FILE 
    { "global" : { 
    "name" : "dsa", 
    "id" : 1 } } 
+3

ein kleiner Tipp, nicht als root anmelden, um die Arbeit zu tun. – Kent

Antwort

4

Ihr einziges Problem war, dass das Skript zu jq geben wurde falsch zitiert.

In Ihrem speziellen Fall eine einzelne Strings in doppelten Anführungszeichen mit eingebetteten \ -escaped " Instanzen verwendet, ist wohl am einfachsten:

jq -r ".global.name = \"$INPUT\"" "$CONF_FILE" > tmp.$$.json && mv tmp.$$.json "$CONF_FILE" 

Im Allgemeinen jedoch chepner's helpful answer zeigt eine robustere Alternative, um die Shell-Variable auf das Einbetten Referenz direkt im Skript: Mit der --arg Option, um einen Wert als jqVariable ermöglicht single-quotein übergeben g das Skript, was bevorzugt ist, weil es Verwirrung über vermeidet, welche Elemente von der Shell vorne erweitert werden und vermeidet die Notwendigkeit $ Instanzen zu entkommen, die durch zu jq übergeben werden sollen.

auch:

  • Gerade = ausreicht, um den Wert zuzuweisen; während |=, der sogenannte Update-Operator, auch funktioniert, verhält es sich in diesem Fall genauso wie =, weil der RHS ein Literal ist, kein Ausdruck, der die LHS referenziert - siehe the manual.
  • Sie sollten routinemäßig doppelte Anführungszeichen Shell-Variablenreferenzen und Sie sollten die Verwendung von all-Großvariablennamen, um avoid conflicts with environment variables and special shell variables zu vermeiden.

Was , warum Ihr zitiert habe nicht:

'.global.name |= '""$INPUT"" setzt sich aus den folgenden Token:

  • Stringliteral .global.name |= (durch Einzel zitieren)
  • Zeichenfolge literal "" - dhDie leere Zeichenfolge - die Anführungszeichen entfernt von der Shell sein wird, bevor das Skript jq
  • Ein unquoted Bezug auf variable $INPUT (die ihren Wert in einzelne Wörter spalt macht und Globbing) sieht.
  • Eine andere Instanz von Literal "".

Mit Ihrem Sample-Wert, beendeten jq die folgende Zeichenfolge als Skript zu sehen, oben:

.global.name |= dsa 

Wie Sie sehen können, die doppelten Anführungszeichen fehlen, jq verursachte dsa als Funktionsnamen zu interpretieren anstelle eines String-Literals, und da kein Argument an (nicht existent) Funktion übergeben wurde dsa, jq Fehlermeldung verweist als dsa/0 - eine Funktion mit keine (0) Argumente.

1

Mit jq mit einem geraden Vorwärtsfilter, sollte es für Sie tun.

.global.name = "dsa" 

heißt

jq '.global.name = "dsa"' json-file 
{ 
    "global": { 
    "name": "dsa", 
    "id": 1 
    } 
} 

Sie können mit Ihrem json-filters rumspielen, here.

+1

'| =' war nicht das Problem; das Zitat war. – chepner

+0

@chepner: habe es früher nicht verstanden. – Inian

+1

Beachten Sie auch, dass _filter_ ist ein sehr breites Konzept in 'jq' (Zitat aus dem [Handbuch] (https://stedolan.github.io/jq/manual/): 'Ein jq-Programm ist ein" Filter ": es nimmt eine Eingabe und erzeugt eine Ausgabe. '), während das Merkmal von Interesse ist hier eine _assignment_. – mklement0

4

Es ist viel einfacher und sicherer, den Wert zu übergeben die --arg Option:

jq -r --arg newname "$INPUT" '.global.name |= $newname' "$CONF_FILE" 

Dies stellt sicher, dass der genaue Wert von $INPUT verwendet wird und als JSON-Wert angegeben.

Verwandte Themen