Analysieren von JSON mit Unix-Tools

879

Ich versuche, JSON zu analysieren, das von einer Curl-Anfrage zurückgegeben wurde, wie folgt:

curl 'http://twitter.com/users/username.json' |
    sed -e 's/[{}]/''/g' | 
    awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'

Das obige teilt den JSON in Felder auf, zum Beispiel:

% ...
"geo_enabled":false
"friends_count":245
"profile_text_color":"000000"
"status":"in_reply_to_screen_name":null
"source":"web"
"truncated":false
"text":"My status"
"favorited":false
% ...

Wie drucke ich ein bestimmtes Feld (gekennzeichnet durch -v k=text)?

Ein Benutzer
quelle
5
Ähm, das ist nicht gut, json parsing btw ... was ist mit den Escape-Zeichen in Strings ... usw. Gibt es eine Python-Antwort auf SO (sogar eine Perl-Antwort ...)?
Martinr
51
Jedes Mal, wenn jemand sagt "Problem X kann leicht mit einer anderen Sprache Y gelöst werden", lautet der Code für "Meine Werkzeugkiste hat nur einen Stein zum Einschlagen von Nägeln ... warum sollte ich mich um irgendetwas anderes kümmern?"
BryanH
22
@BryanH: außer manchmal die Sprache Y kann mehr ausgestattet sein besonderes Problem X zu lösen , unabhängig davon , wie viele Sprachen die Person , die Y vorgeschlagen weiß.
JFS
15
Ein bisschen spät, aber hier geht es. grep -Po '"'"version"'"\s*:\s*"\K([^"]*)' package.json. Dies löst die Aufgabe einfach und nur mit grep und funktioniert perfekt für einfache JSONs. Für komplexe JSONs sollten Sie einen geeigneten Parser verwenden.
Diosney
2
@auser, wäre es in Ordnung, wenn Sie im Titel "mit sed und awk" in "mit UNIX-Tools" ändern würden?
Charles Duffy

Antworten:

1127

Es gibt eine Reihe von Tools, die speziell für die Bearbeitung von JSON über die Befehlszeile entwickelt wurden und viel einfacher und zuverlässiger sind als Awk, z. B jq.:

curl -s 'https://api.github.com/users/lambda' | jq -r '.name'

Sie können dies auch mit Tools tun, die wahrscheinlich bereits auf Ihrem System installiert sind, wie z. B. Python, das das jsonModul verwendet , und so zusätzliche Abhängigkeiten vermeiden, während Sie dennoch den Vorteil eines geeigneten JSON-Parsers haben. Im Folgenden wird davon ausgegangen, dass Sie UTF-8 verwenden möchten, in dem der ursprüngliche JSON-Code codiert sein sollte und das auch von den meisten modernen Terminals verwendet wird:

Python 3:

curl -s 'https://api.github.com/users/lambda' | \
    python3 -c "import sys, json; print(json.load(sys.stdin)['name'])"

Python 2:

export PYTHONIOENCODING=utf8
curl -s 'https://api.github.com/users/lambda' | \
    python2 -c "import sys, json; print json.load(sys.stdin)['name']"

Historische Notizen

Diese Antwort empfahl ursprünglich jsawk , das zwar immer noch funktionieren sollte, aber etwas umständlicher zu verwenden ist als jqund von der Installation eines eigenständigen JavaScript-Interpreters abhängt, der weniger verbreitet ist als ein Python-Interpreter. Daher sind die obigen Antworten wahrscheinlich vorzuziehen:

curl -s 'https://api.github.com/users/lambda' | jsawk -a 'return this.name'

Diese Antwort verwendete ursprünglich auch die Twitter-API aus der Frage, aber diese API funktioniert nicht mehr, was es schwierig macht, die Beispiele zum Testen zu kopieren, und die neue Twitter-API erfordert API-Schlüssel, daher habe ich auf die Verwendung der GitHub-API umgestellt, die kann leicht ohne API-Schlüssel verwendet werden. Die erste Antwort auf die ursprüngliche Frage wäre:

curl 'http://twitter.com/users/username.json' | jq -r '.text'
Brian Campbell
quelle
7
@thrau +1. jq es ist im Repository verfügbar und super einfach zu bedienen, daher ist es viel besser als jsawk. Ich habe beide für ein paar Minuten getestet, jq hat diesen Kampf gewonnen
Szymon Sadło
1
Beachten Sie, dass in Python 2 die printAnweisung immer in ASCII codiert wird , wenn Sie die Ausgabe an einen anderen Befehl weiterleiten, da Sie Python in einer Pipe verwenden. Fügen Sie PYTHONIOENCODING=<desired codec>in den Befehl ein, um eine andere Ausgabecodierung festzulegen, die für Ihr Terminal geeignet ist. In Python 3 ist in diesem Fall der Standardwert UTF-8 (mithilfe der print() Funktion ).
Martijn Pieters
1
Installieren Sie jq unter OSX mit Brew
Andy Fraley
1
curl -sist äquivalent zu curl --silent, während jq -rbedeutet jq --raw-outputdh ohne Anführungszeichen.
Serge Stroobandt
python -c "Importanfragen; r = request.get (' api.github.com/users/lambda');print r.json () [' name '];" . Das einfachste!
NotTooTechy
277

Um die Werte für einen bestimmten Schlüssel schnell zu extrahieren, verwende ich persönlich gerne "grep -o", das nur die Übereinstimmung des regulären Ausdrucks zurückgibt. Zum Beispiel, um das "Text" -Feld aus Tweets zu erhalten, etwa:

grep -Po '"text":.*?[^\\]",' tweets.json

Diese Regex ist robuster als Sie vielleicht denken; Beispielsweise werden Zeichenfolgen mit eingebetteten Kommas und Anführungszeichen gut behandelt. Ich denke, mit etwas mehr Arbeit könnten Sie eine machen, die tatsächlich garantiert den Wert extrahiert, wenn sie atomar ist. (Wenn es verschachtelt ist, kann ein Regex das natürlich nicht.)

Und um weiter zu reinigen (obwohl das Original der Saite erhalten bleibt), können Sie Folgendes verwenden : | perl -pe 's/"text"://; s/^"//; s/",$//'. (Ich habe dies für diese Analyse getan .)

Für alle Hasser, die darauf bestehen, dass Sie einen echten JSON-Parser verwenden - ja, das ist für die Korrektheit unerlässlich, aber

  1. Um eine wirklich schnelle Analyse durchzuführen, z. B. das Zählen von Werten, um Fehler bei der Datenbereinigung zu überprüfen oder ein allgemeines Gefühl für die Daten zu bekommen, ist es schneller, etwas in der Befehlszeile herauszuschlagen. Das Öffnen eines Editors zum Schreiben eines Skripts lenkt ab.
  2. grep -oist um Größenordnungen schneller als die Python-Standardbibliothek json, zumindest wenn dies für Tweets durchgeführt wird (die jeweils ~ 2 KB groß sind). Ich bin mir nicht sicher, ob dies nur deshalb jsonso langsam ist (ich sollte es irgendwann mit yajl vergleichen). Im Prinzip sollte ein Regex jedoch schneller sein, da er endlich ist und viel besser optimiert werden kann, anstatt eines Parsers, der die Rekursion unterstützen muss, und in diesem Fall viele CPU-Gebäudebäume für Strukturen ausgibt, die Sie nicht interessieren. (Wenn jemand einen Finite-State-Transducer geschrieben hätte, der eine ordnungsgemäße (tiefenbegrenzte) JSON-Analyse durchgeführt hat, wäre das fantastisch! In der Zwischenzeit haben wir "grep -o".)

Um wartbaren Code zu schreiben, verwende ich immer eine echte Parsing-Bibliothek. Ich habe jsawk noch nicht ausprobiert , aber wenn es gut funktioniert, würde das Punkt 1 ansprechen.

Eine letzte, verrücktere Lösung: Ich habe ein Skript geschrieben, das Python verwendet jsonund die gewünschten Schlüssel in durch Tabulatoren getrennte Spalten extrahiert. dann leite ich einen Wrapper um awk, der den benannten Zugriff auf Spalten ermöglicht. Hier: die Skripte json2tsv und tsvawk . Für dieses Beispiel wäre es also:

json2tsv id text < tweets.json | tsvawk '{print "tweet " $id " is: " $text}'

Dieser Ansatz geht nicht auf Nummer 2 ein, ist ineffizienter als ein einzelnes Python-Skript und ein wenig spröde: Er erzwingt die Normalisierung von Zeilenumbrüchen und Tabulatoren in Zeichenfolgenwerten, um mit der durch Felder / Datensätze getrennten Weltansicht von awk gut zu spielen. Damit können Sie jedoch korrekter als in der Befehlszeile bleiben grep -o.

Brendan OConnor
quelle
11
Sie haben ganzzahlige Werte vergessen. grep -Po '"text":(\d*?,|.*?[^\\]",)'
Robert
3
Robert: Richtig, mein regulärer Ausdruck wurde nur für Zeichenfolgenwerte für dieses Feld geschrieben. Ganzzahlen können wie gesagt hinzugefügt werden. Wenn Sie alle Typen wollen, müssen Sie immer mehr tun: Boolesche Werte, Null. Und Arrays und Objekte erfordern mehr Arbeit. Unter Standard-Regexen ist nur eine Tiefenbegrenzung möglich.
Brendan OConnor
9
1. jq .namearbeitet in der Befehlszeile und erfordert nicht "Öffnen eines Editors zum Schreiben eines Skripts". 2. Es spielt keine Rolle, wie schnell Ihre Regex zu falschen Ergebnissen führen kann
jfs
6
und wenn Sie nur die Werte wollen, können Sie einfach awk darauf werfen. | grep -Po '"text":.*?[^\\]",'|awk -F':' '{print $2}'
JeffCharter
34
Es scheint, dass unter OSX die -POption fehlt. Ich habe unter OSX 10.11.5 getestet und grep --versionwar grep (BSD grep) 2.5.1-FreeBSD. Ich habe es mit der Option "Extended Regex" unter OSX zum Laufen gebracht. Der Befehl von oben wäre grep -Eo '"text":.*?[^\\]",' tweets.json.
Jens
174

Aufgrund der Tatsache, dass einige der Empfehlungen hier (insbesondere in den Kommentaren) die Verwendung von Python vorschlugen, war ich enttäuscht, kein Beispiel zu finden.

Hier ist also ein Einzeiler, um einen einzelnen Wert aus einigen JSON-Daten zu erhalten. Es wird davon ausgegangen, dass Sie die Daten (von irgendwoher) weiterleiten und daher in einem Skriptkontext nützlich sein sollten.

echo '{"hostname":"test","domainname":"example.com"}' | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["hostname"]'
paulkmoore
quelle
Ich habe diese Antwort unten erweitert, um eine Bash-Funktion zu verwenden: curl 'some_api' | getJsonVal 'key'
Joe Heyming
pythonpy( github.com/russell91/pythonpy ist fast immer eine bessere Alternative zu python -c, obwohl es mit pip installiert werden muss. Pipe einfach den json an py --ji -x 'x[0]["hostname"]'. Wenn Sie die eingebaute json_input-Unterstützung nicht verwenden möchten, können Sie sie trotzdem erhalten Diese importieren automatisch alspy 'json.loads(sys.stdin)[0]["hostname"]'
RussellStewart
2
Vielen Dank! Für ein schnelleres und schmutzigeres JSON-Parsing habe ich es in eine Bash-Funktion eingewickelt: jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); print($1)"; }damit ich schreiben kann: curl ...... | jsonq 'json.dumps([key["token"] for key in obj], indent=2)'& mehr ähnliche beängstigende Dinge ... Übrigens, obj[0]scheint unnötig, es sieht so aus, als ob es objin Standardfällen nur in Ordnung ist (?).
akavel
Vielen Dank. Ich habe diesen Respekt JSON ein bisschen besser gemacht als Print:jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); sys.stdout.write(json.dumps($1))"; }
Adam K Dean
4
obj[0]verursacht beim Parsen einen Fehler { "port":5555 }. Funktioniert gut nach dem Entfernen [0].
CyberEd
134

Nach MartinR und Boeckos Führung:

$ curl -s 'http://twitter.com/users/username.json' | python -mjson.tool

Dadurch erhalten Sie eine äußerst grep-freundliche Ausgabe. Sehr angenehm:

$ curl -s 'http://twitter.com/users/username.json' | python -mjson.tool | grep my_key
jnrg
quelle
37
Wie würden Sie einen bestimmten Schlüssel extrahieren, wie OP fragt?
Juan
2
Die beste Antwort bisher imho, Sie müssen auf den meisten Distributionen nichts anderes installieren, und Sie können | grep field. Vielen Dank!
Andrea Richiardi
7
Alles, was dies tut, ist das Formatieren des JSON, wenn ich mich nicht irre. Es erlaubt dem Aufrufer nicht, ein bestimmtes Feld aus der Ausgabe auszuwählen, wie dies bei einer xpath-Lösung oder etwas basierend auf "JSON Pointer" der Fall wäre.
Cheeso
4
Am Ende habe ich nur ein Schlüsselwertpaar, aber nicht den Wert an und für sich.
Christopher
1
jqwird normalerweise nicht installiert, während Python ist. Sobald Sie in Python sind, können Sie auch den ganzen Weg gehen und ihn analysieren mitimport json...
CpILL
125

Sie können einfach Binärdateien für Ihre Plattform herunterladenjq und ( chmod +x jq) ausführen :

$ curl 'https://twitter.com/users/username.json' | ./jq -r '.name'

Es extrahiert "name"Attribute aus dem JSON-Objekt.

jqDie Homepage sagt, es sei wie sedbei JSON-Daten.

jfs
quelle
27
Nur für die Aufzeichnung, jqist ein erstaunliches Werkzeug.
Hoss
2
Einverstanden. Ich kann nicht mit jsawk aus der akzeptierten Antwort vergleichen, da ich das nicht verwendet habe, aber für lokale Experimente (wo die Installation eines Tools akzeptabel ist) empfehle ich jq. Hier ist ein etwas ausführlicheres Beispiel, das jedes Element eines Arrays nimmt und ein neues JSON-Objekt mit ausgewählten Daten synthetisiert: curl -s https://api.example.com/jobs | jq '.jobs[] | {id, o: .owner.username, dateCreated, s: .status.state}'
Jbyler
2
Ich liebe das. Sehr leicht und da es in einfachem altem C ist, kann es fast überall kompiliert werden.
Benmj
1
Das praktischste: Es benötigt keine Bibliotheken von Drittanbietern (während jsawk dies tut) und ist einfach zu installieren (OSX: Brew Install JQ)
Lauhub
1
Dies ist die praktischste und am einfachsten zu implementierende Antwort für meinen Anwendungsfall. Für das Ubuntu (14.04) System hat eine einfache apt-get install jq das Tool zu meinem System hinzugefügt. Ich leite die JSON-Ausgabe von AWS CLI-Antworten an jq weiter und es funktioniert hervorragend, Werte in bestimmte Schlüssel zu extrahieren, die in der Antwort verschachtelt sind.
Brandon K
105

Verwenden von Node.js.

Wenn das System hat Bei der Installation können Sie die Skriptflags -pprint und -eevaulate verwenden JSON.parse, um den erforderlichen Wert abzurufen .

Ein einfaches Beispiel mit der JSON-Zeichenfolge { "foo": "bar" }und dem Herausziehen des Werts "foo":

$ node -pe 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'
bar

Da wir Zugriff auf catund andere Dienstprogramme haben, können wir dies für Dateien verwenden:

$ node -pe 'JSON.parse(process.argv[1]).foo' "$(cat foobar.json)"
bar

Oder ein anderes Format wie eine URL, die JSON enthält:

$ node -pe 'JSON.parse(process.argv[1]).name' "$(curl -s https://api.github.com/users/trevorsenior)"
Trevor Senior
JayQuerie.com
quelle
1
Vielen Dank! aber in meinem Fall funktioniert es nur mit -e Flagnode -p -e 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'
Rnd_d
33
Pfeifen! curl -s https://api.github.com/users/trevorsenior | node -pe "JSON.parse(require('fs').readFileSync('/dev/stdin').toString()).name"
Nicerobot
4
das ist meine Lieblingslösung; Verwenden Sie eine Sprache (Javascript), um eine für sie natürliche Datenstruktur (JSON) zu analysieren. scheint am richtigsten . Außerdem ist der Knoten wahrscheinlich bereits auf dem System verfügbar, und Sie müssen nicht mit den Binärdateien von jq arbeiten (was wie eine andere richtige Wahl aussieht ).
Eliran Malka
Dies ist die Bash-Skriptfunktion: # jsonv ruft den json-Objektwert für ein bestimmtes Attribut ab # erster Parameter ist das json-Dokument # zweiter Parameter ist das Attribut, dessen Wert zurückgegeben werden soll get_json_attribute_value () {node -pe 'JSON.parse (process. argv [1]) [process.argv [2]] '"$ 1" "$ 2"}
Youness
6
Das Folgende funktioniert mit Node.js 10:cat package.json | node -pe 'JSON.parse(fs.readFileSync(0)).version'
Ilya Boyandin
100

Verwenden Sie die JSON-Unterstützung von Python anstelle von awk!

Etwas wie das:

curl -s http://twitter.com/users/username.json | \
    python -c "import json,sys;obj=json.load(sys.stdin);print obj['name'];"
martinr
quelle
6
Verzeihen Sie mir, dass ich versucht habe, eine gute Antwort zu finden ...: Ich werde mich mehr anstrengen. Parteilichkeit erfordert mehr als das Schreiben eines awk-Skripts, um es abzuschütteln!
Martinr
9
Warum verwenden Sie die Variable obj in dieser Oneliner-Lösung? Es ist nutzlos und wird überhaupt nicht gespeichert? Sie schreiben weniger json.load(sys.stdin)['"key']"als Beispiel wie : curl -sL httpbin.org/ip | python -c "import json,sys; print json.load(sys.stdin)['origin']".
m3nda
65

Sie haben gefragt, wie Sie sich in den Fuß schießen sollen, und ich bin hier, um die Munition bereitzustellen:

curl -s 'http://twitter.com/users/username.json' | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^text/ {print $2}'

Sie könnten tr -d '{}'anstelle von verwenden sed. Aber sie komplett wegzulassen scheint auch den gewünschten Effekt zu haben.

Wenn Sie die äußeren Anführungszeichen entfernen möchten, leiten Sie das Ergebnis der obigen Angaben durch sed 's/\(^"\|"$\)//g'

Ich denke, andere haben ausreichend Alarm geschlagen. Ich werde mit einem Handy bereitstehen, um einen Krankenwagen zu rufen. Feuer, wenn es fertig ist.

Bis auf weiteres angehalten.
quelle
10
Auf diese Weise liegt der Wahnsinn, lesen Sie
Folgendes
3
Ich habe alle Antworten gelesen und diese funktioniert perfekt für mich ohne zusätzliche Abhängigkeiten. +1
eth0
Das habe ich gesucht. Die einzige Korrektur - vorausgesetzt, der Befehl sed zum Entfernen von Anführungszeichen hat bei mir nicht funktioniert. Ich habe stattdessen sed 's / "// g' verwendet
AlexG
44

Verwenden von Bash mit Python

Erstellen Sie eine Bash-Funktion in Ihrer .bash_rc-Datei

function getJsonVal () { 
    python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))"; 
}

Dann

$ curl 'http://twitter.com/users/username.json' | getJsonVal "['text']"
My status
$ 

Hier ist die gleiche Funktion, jedoch mit Fehlerprüfung.

function getJsonVal() {
   if [ \( $# -ne 1 \) -o \( -t 0 \) ]; then
       cat <<EOF
Usage: getJsonVal 'key' < /tmp/
 -- or -- 
 cat /tmp/input | getJsonVal 'key'
EOF
       return;
   fi;
   python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))";
}

Wobei $ # -ne 1 mindestens 1 Eingabe sicherstellt und -t 0 sicherstellt, dass Sie von einer Pipe umleiten.

Das Schöne an dieser Implementierung ist, dass Sie auf verschachtelte JSON-Werte zugreifen und dafür JSON erhalten können! =)

Beispiel:

$ echo '{"foo": {"bar": "baz", "a": [1,2,3]}}' |  getJsonVal "['foo']['a'][1]"
2

Wenn Sie wirklich ausgefallen sein möchten, können Sie die Daten hübsch ausdrucken:

function getJsonVal () { 
    python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1, sort_keys=True, indent=4))"; 
}

$ echo '{"foo": {"bar": "baz", "a": [1,2,3]}}' |  getJsonVal "['foo']"
{
    "a": [
        1, 
        2, 
        3
    ], 
    "bar": "baz"
}
Joe Heyming
quelle
curl http://foo | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["environment"][0]["name"]'
Einzeiler
1
sys.stdout.write()Wenn Sie möchten, dass es sowohl mit Python 2 als auch mit Python 3 funktioniert.
Per Johansson
Ich denke, dass es sich in system.stdout.write ändern sollte (obj $ 1). Auf diese Weise können Sie sagen: getJsonVal "['environment'] ['name']", wie @Cheesos Beispiel
Joe Heyming
1
@ Narek In diesem Fall würde es so aussehen: FunktiongetJsonVal() { py -x "json.dumps(json.loads(x)$1, sort_keys=True, indent=4)"; }
Joe Heyming
30

TickTick ist ein in Bash geschriebener JSON-Parser (<250 Codezeilen)

Hier ist der Ausschnitt des Autors aus seinem Artikel " Stellen Sie sich eine Welt vor, in der Bash JSON unterstützt :

#!/bin/bash
. ticktick.sh

``  
  people = { 
    "Writers": [
      "Rod Serling",
      "Charles Beaumont",
      "Richard Matheson"
    ],  
    "Cast": {
      "Rod Serling": { "Episodes": 156 },
      "Martin Landau": { "Episodes": 2 },
      "William Shatner": { "Episodes": 2 } 
    }   
  }   
``  

function printDirectors() {
  echo "  The ``people.Directors.length()`` Directors are:"

  for director in ``people.Directors.items()``; do
    printf "    - %s\n" ${!director}
  done
}   

`` people.Directors = [ "John Brahm", "Douglas Heyes" ] ``
printDirectors

newDirector="Lamont Johnson"
`` people.Directors.push($newDirector) ``
printDirectors

echo "Shifted: "``people.Directors.shift()``
printDirectors

echo "Popped: "``people.Directors.pop()``
printDirectors
CoolAJ86
quelle
2
Als einzige robuste Pure-Bash-Antwort hier verdient dies mehr positive Stimmen.
Ed Randall
Gibt es eine Möglichkeit, diese Personenvariable erneut in eine JSON-Zeichenfolge zu drucken? Das wäre äußerst nützlich
Thomas Fournet
1
Endlich eine Antwort, die Python oder andere grausame Methoden nicht empfiehlt ... Danke!
Akito
21

Analysieren von JSON mit PHP CLI

Wohl nicht zum Thema, aber da Vorrang herrscht, bleibt diese Frage unvollständig, ohne dass unser vertrauenswürdiges und treues PHP erwähnt wird. Stimmt das?

Verwenden Sie dasselbe Beispiel für JSON, aber lassen Sie es einer Variablen zuweisen, um die Dunkelheit zu verringern.

$ export JSON='{"hostname":"test","domainname":"example.com"}'

Nun zur PHP-Güte, mit file_get_contents und dem Stream-Wrapper php: // stdin .

$ echo $JSON|php -r 'echo json_decode(file_get_contents("php://stdin"))->hostname;'

oder wie unter Verwendung von fgets und dem bereits geöffneten Stream bei der CLI-Konstante STDIN hervorgehoben .

$ echo $JSON|php -r 'echo json_decode(fgets(STDIN))->hostname;'

nJoy!

Nickl-
quelle
Sie können sogar $argnanstelle vonfgets(STDIN)
IcanDivideBy0
Hoppla, $argnfunktioniert mit dem Flag -E oder -R und nur, wenn sich der JSON-Inhalt in einer Zeile befindet ...
IcanDivideBy0
21

Native Bash-Version: Funktioniert auch gut mit Backslashes (\) und Anführungszeichen (")

function parse_json()
{
    echo $1 | \
    sed -e 's/[{}]/''/g' | \
    sed -e 's/", "/'\",\"'/g' | \
    sed -e 's/" ,"/'\",\"'/g' | \
    sed -e 's/" , "/'\",\"'/g' | \
    sed -e 's/","/'\"---SEPERATOR---\"'/g' | \
    awk -F=':' -v RS='---SEPERATOR---' "\$1~/\"$2\"/ {print}" | \
    sed -e "s/\"$2\"://" | \
    tr -d "\n\t" | \
    sed -e 's/\\"/"/g' | \
    sed -e 's/\\\\/\\/g' | \
    sed -e 's/^[ \t]*//g' | \
    sed -e 's/^"//'  -e 's/"$//'
}


parse_json '{"username":"john, doe","email":"[email protected]"}' username
parse_json '{"username":"john doe","email":"[email protected]"}' email

--- outputs ---

john, doe
johh@doe.com
maikel
quelle
Das ist fantastisch. Wenn die JSON-Zeichenfolge jedoch mehr als einen E-Mail-Schlüssel enthält, gibt der Parser [email protected] "" [email protected]
rtc11
Funktioniert nicht, wenn die E-Mail einen Strich wie [email protected] enthält
alexmngn
13

Version, die Ruby und http://flori.github.com/json/ verwendet

$ < file.json ruby -e "require 'rubygems'; require 'json'; puts JSON.pretty_generate(JSON[STDIN.read]);"

oder genauer:

$ < file.json ruby -r rubygems -r json -e "puts JSON.pretty_generate(JSON[STDIN.read]);"
Boecko
quelle
3
das ist mein Favorit;) Übrigens können Sie es mit ruby-rjson kurzschließen, um die Bibliothek zu benötigen
lucapette
Beachten Sie, dass das Finale ;in Ruby nicht erforderlich ist (es wird nur zum Verketten von Anweisungen verwendet, die normalerweise in separaten Zeilen zu einer einzelnen Zeile stehen).
Zack Morris
11

Leider ist die oben gestimmt Antwort , dass Anwendungen grepgibt die volle Übereinstimmung, die nicht Arbeit in meinem Szenario tat, aber wenn Sie wissen , das JSON - Format konstant bleiben können Sie verwenden Lookbehind und Look - Ahead nur die gewünschten Werte zu extrahieren.

# echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="FooBar":")(.*?)(?=",)'
he\"llo
# echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="TotalPages":)(.*?)(?=,)'
33
#  echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="anotherValue":)(.*?)(?=})'
100
Daniel Sokolowski
quelle
Sie nie wirklich wissen , die Reihenfolge der Elemente in einem JSON - Wörterbuch. Sie sind per Definition ungeordnet. Dies ist genau einer der fundamentalen Gründe, warum das Rollen Ihres eigenen JSON-Parsers zum Scheitern verurteilt ist.
Tripleee
10

Wenn jemand nur Werte aus einfachen JSON-Objekten extrahieren möchte, ohne dass verschachtelte Strukturen erforderlich sind, können reguläre Ausdrücke verwendet werden, ohne die Bash zu verlassen.

Hier ist eine Funktion, die ich mithilfe von regulären Bash-Ausdrücken basierend auf dem JSON-Standard definiert habe :

function json_extract() {
  local key=$1
  local json=$2

  local string_regex='"([^"\]|\\.)*"'
  local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
  local value_regex="${string_regex}|${number_regex}|true|false|null"
  local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"

  if [[ ${json} =~ ${pair_regex} ]]; then
    echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
  else
    return 1
  fi
}

Vorsichtsmaßnahmen: Objekte und Arrays werden nicht als Wert unterstützt, aber alle anderen im Standard definierten Werttypen werden unterstützt. Außerdem wird ein Paar abgeglichen, unabhängig davon, wie tief es im JSON-Dokument ist, solange es genau denselben Schlüsselnamen hat.

Am Beispiel von OP:

$ json_extract text "$(curl 'http://twitter.com/users/username.json')"
My status

$ json_extract friends_count "$(curl 'http://twitter.com/users/username.json')"
245
Helder Pereira
quelle
Helder Pereira können wir mit dieser Funktion verschachtelte Eigenschaftswerte extrahieren?
vsbehere
8

Es gibt eine einfachere Möglichkeit, eine Eigenschaft aus einer JSON-Zeichenfolge abzurufen. package.jsonVersuchen Sie dies am Beispiel einer Datei:

#!/usr/bin/env bash
my_val="$(json=$(<package.json) node -pe "JSON.parse(process.env.json)['version']")"

Wir verwenden, process.envweil dadurch der Inhalt der Datei als Zeichenfolge in node.js übertragen wird, ohne dass das Risiko besteht, dass böswillige Inhalte aus dem Zitat entweichen und als Code analysiert werden.

Alexander Mills
quelle
Durch die Verwendung der Zeichenfolgenverkettung zum Ersetzen von Werten in eine als Code analysierte Zeichenfolge kann ein beliebiger node.js-Code ausgeführt werden. Dies bedeutet, dass die Verwendung mit zufälligen Inhalten, die Sie aus dem Internet erhalten haben, äußerst unsicher ist. Es gibt einen Grund, warum sichere / bewährte Methoden zum Parsen von JSON in JavaScript nicht nur ausgewertet werden.
Charles Duffy
@CharlesDuffy nicht sicher, ob ich folge, aber der JSON.parse-Aufruf sollte sicherer sein, da require()tatsächlich Fremdcode ausgeführt werden kann, JSON.parse nicht.
Alexander Mills
Dies gilt nur dann, wenn Ihre Zeichenfolge tatsächlich so in die JSON-Laufzeit eingefügt wird, dass der Parser umgangen wird. Ich sehe den Code hier nicht zuverlässig. Ziehen Sie es aus einer Umgebungsvariablen und übergeben Sie es an JSON.parse()und ja, Sie sind eindeutig sicher ... aber hier empfängt die JSON-Laufzeit den (nicht vertrauenswürdigen) Inhalt im Band mit dem (vertrauenswürdigen) Code.
Charles Duffy
... Wenn Sie Ihren Code den JSON aus der Datei als Zeichenfolge lesen und an diese übergeben lassen, JSON.parse()sind Sie ebenfalls sicher, aber das passiert auch hier nicht.
Charles Duffy
1
... ahh, zum Teufel, könnte genauso gut sofort ins "Wie" gehen. Das Problem ist, dass Sie die Shell-Variable, an die Sie übergeben werden möchten JSON.parse(), in den Code einsetzen . Sie gehen davon aus, dass das Setzen von Literal-Backticks den Inhalt wörtlich hält, aber das ist eine völlig unsichere Annahme, da Literal-Backticks im Dateiinhalt (und damit in der Variablen) vorhanden sein können und somit das Anführungszeichen beenden und in einen nicht zitierten Kontext eintreten können, in dem die Werte werden als Code ausgeführt.
Charles Duffy
7

Jetzt, da Powershell plattformübergreifend ist, dachte ich, ich würde mich da rauswerfen, da ich finde, dass es ziemlich intuitiv und extrem einfach ist.

curl -s 'https://api.github.com/users/lambda' | ConvertFrom-Json 

ConvertFrom-Json konvertiert den JSON in ein benutzerdefiniertes Powershell-Objekt, sodass Sie von diesem Punkt an problemlos mit den Eigenschaften arbeiten können. Wenn Sie zum Beispiel nur die Eigenschaft 'id' möchten, tun Sie dies einfach:

curl -s 'https://api.github.com/users/lambda' | ConvertFrom-Json | select -ExpandProperty id

Wenn Sie das Ganze aus Bash heraus aufrufen möchten, müssen Sie es so nennen:

powershell 'curl -s "https://api.github.com/users/lambda" | ConvertFrom-Json'

Natürlich gibt es eine reine Powershell-Methode, um es ohne Locken zu machen.

Invoke-WebRequest 'https://api.github.com/users/lambda' | select -ExpandProperty Content | ConvertFrom-Json

Schließlich gibt es noch 'ConvertTo-Json', das ein benutzerdefiniertes Objekt genauso einfach in JSON konvertiert. Hier ist ein Beispiel:

(New-Object PsObject -Property @{ Name = "Tester"; SomeList = @('one','two','three')}) | ConvertTo-Json

Welches würde schönes JSON wie dieses produzieren:

{
"Name":  "Tester",
"SomeList":  [
                 "one",
                 "two",
                 "three"
             ]

}}

Zugegeben, die Verwendung einer Windows-Shell unter Unix ist etwas sakrilegisch, aber Powershell ist in einigen Dingen wirklich gut, und das Parsen von JSON und XML sind einige davon. Dies ist die GitHub-Seite für die plattformübergreifende Version https://github.com/PowerShell/PowerShell

user2233949
quelle
Upvoted, weil Sie für die neue Microsoft-Strategie werben, Open-Source-Tools zu verwenden und Open-Source-Fremdtools zu integrieren. Es ist eine gute Sache für unsere Welt.
Alex
Früher mochte ich PowerShell nicht, aber ich muss zugeben, dass der Umgang mit JSON als Objekte ziemlich gut ist.
MartinThé
6

Jemand, der auch XML-Dateien hat, möchte sich vielleicht meinen Xidel ansehen . Es ist ein cli, abhängigkeitsfreies JSONiq Prozessor. (dh es unterstützt auch XQuery für die XML- oder JSON-Verarbeitung)

Das Beispiel in der Frage wäre:

 xidel -e 'json("http://twitter.com/users/username.json")("name")'

Oder mit meiner eigenen, nicht standardmäßigen Erweiterungssyntax:

 xidel -e 'json("http://twitter.com/users/username.json").name'
BeniBela
quelle
1
Oder heutzutage einfacher: xidel -s https://api.github.com/users/lambda -e 'name'(oder -e '$json/name', oder -e '($json).name').
Reino
6

Ich kann hier keine der Antworten verwenden. Kein verfügbares JQ, keine Shell-Arrays, kein Deklarieren, kein Grep-P, kein Lookbehind und Lookahead, kein Python, kein Perl, kein Ruby, nein - nicht einmal Bash ... Die verbleibenden Antworten funktionieren einfach nicht gut. JavaScript kam mir bekannt vor, aber in der Dose steht Nescaffe - also ist es auch ein No-Go :) Selbst wenn es für meine einfache Notwendigkeit verfügbar wäre, wären sie übertrieben und langsam.

Für mich ist es jedoch äußerst wichtig, viele Variablen aus der json-formatierten Antwort meines Modems zu erhalten. Ich mache es in einem Sh mit sehr abgespeckten BusyBox an meinen Routern! Keine Probleme mit awk alleine: Setzen Sie einfach Trennzeichen und lesen Sie die Daten. Für eine einzelne Variable ist das alles!

awk 'BEGIN { FS="\""; RS="," }; { if ($2 == "login") {print $4} }' test.json

Erinnerst du dich, dass ich keine Arrays habe? Ich musste innerhalb der awk-analysierten Daten den 11 Variablen zuweisen, die ich in einem Shell-Skript benötige. Wo immer ich hinschaute, wurde gesagt, dass dies eine unmögliche Mission sei. Auch damit kein Problem.

Meine Lösung ist einfach. Dieser Code wird: 1) die .json-Datei aus der Frage analysieren (tatsächlich habe ich ein Arbeitsdatenbeispiel aus der am besten bewerteten Antwort ausgeliehen) und die zitierten Daten auswählen, plus 2) Shell-Variablen aus der awk erstellen, die eine frei benannte Shell zuweisen Variablennamen.

eval $( curl -s 'https://api.github.com/users/lambda' | 
awk ' BEGIN { FS="\""; RS="," };
{
    if ($2 == "login") { print "Login=\""$4"\"" }
    if ($2 == "name") { print "Name=\""$4"\"" }
    if ($2 == "updated_at") { print "Updated=\""$4"\"" }
}' )
echo "$Login, $Name, $Updated"

Keine Probleme mit Rohlingen. Bei meiner Verwendung analysiert derselbe Befehl eine lange einzeilige Ausgabe. Da eval verwendet wird, ist diese Lösung nur für vertrauenswürdige Daten geeignet. Es ist einfach, es anzupassen, um nicht zitierte Daten aufzunehmen. Für eine große Anzahl von Variablen kann eine marginale Geschwindigkeitsverstärkung mit else if erreicht werden. Das Fehlen eines Arrays bedeutet offensichtlich: Keine Mehrfachaufzeichnungen ohne zusätzliches Fummeln. Wenn jedoch Arrays verfügbar sind, ist die Anpassung dieser Lösung eine einfache Aufgabe.

@maikel sed Antwort funktioniert fast (aber ich kann es nicht kommentieren). Für meine schön formatierten Daten funktioniert es. Nicht so sehr mit dem hier verwendeten Beispiel (fehlende Anführungszeichen werfen es ab). Es ist kompliziert und schwer zu modifizieren. Außerdem muss ich nicht gerne 11 Aufrufe tätigen, um 11 Variablen zu extrahieren. Warum? Ich habe 100 Schleifen zeitlich festgelegt, um 9 Variablen zu extrahieren: Die sed-Funktion dauerte 48,99 Sekunden und meine Lösung 0,91 Sekunden! Nicht fair? Nur eine einzige Extraktion von 9 Variablen: 0,51 vs. 0,02 Sek.

Pila
quelle
5

Sie können so etwas versuchen -

curl -s 'http://twitter.com/users/jaypalsingh.json' | 
awk -F=":" -v RS="," '$1~/"text"/ {print}'
jaypal singh
quelle
5

Sie können verwenden jshon:

curl 'http://twitter.com/users/username.json' | jshon -e text
kev
quelle
Die Site sagt: "Zweimal so schnell, 1/6 des Speichers" ... und dann: "Jshon analysiert, liest und erstellt JSON. Es ist so konzipiert, dass es innerhalb der Shell so benutzerfreundlich wie möglich ist und fragile Ad-hoc-Parser ersetzt, aus denen es hergestellt wurde grep / sed / awk sowie schwere einzeilige Parser aus Perl / Python. "
Roger
Dies ist als empfohlene Lösung für das Parsen von JSON in Bash
Qodeninja
Was ist der einfachste Weg, um die Anführungszeichen um das Ergebnis herum loszuwerden?
gMale
4

Hier ist eine Möglichkeit, wie Sie es mit awk tun können

curl -sL 'http://twitter.com/users/username.json' | awk -F"," -v k="text" '{
    gsub(/{|}/,"")
    for(i=1;i<=NF;i++){
        if ( $i ~ k ){
            print $i
        }
    }
}'
Ghostdog74
quelle
4

Für eine komplexere JSON-Analyse empfehle ich die Verwendung des Python-Jsonpath-Moduls (von Stefan Goessner) -

  1. Es installieren -

sudo easy_install -U jsonpath

  1. Benutze es -

Beispiel file.json (von http://goessner.net/articles/JsonPath ) -

{ "store": {
    "book": [ 
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

Analysieren Sie es (extrahieren Sie alle Buchtitel mit einem Preis <10) -

$ cat file.json | python -c "import sys, json, jsonpath; print '\n'.join(jsonpath.jsonpath(json.load(sys.stdin), 'store.book[?(@.price < 10)].title'))"

Wird ausgegeben -

Sayings of the Century
Moby Dick

HINWEIS: Die obige Befehlszeile enthält keine Fehlerprüfung. Für eine vollständige Lösung mit Fehlerprüfung sollten Sie ein kleines Python-Skript erstellen und den Code mit try-exception umschließen.

Shlomosh
quelle
schöne Redewendung. Ich kenne Python nicht einmal, aber dies scheint eine mächtige Lösung zu sein
Sridhar Sarnobat
Ich war ein wenig Mühe, die Installation jsonpathso installiert jsonpath_rwstattdessen ist hier so etwas ähnliches Sie , wenn der oben versuchen nicht funktioniert: 1) /usr/bin/python -m pip install jsonpath-rw2) cat ~/trash/file.json | /usr/bin/python -c "from jsonpath_rw import jsonpath, parse; import sys,json; jsonpath_expr = parse('store.book[0]'); out = [match.value for match in jsonpath_expr.find(json.load(sys.stdin))]; print out;"(ich den vollständigen Pfad zum Python binären verwendet , weil ich einige Probleme mit mehreren Pythons aufweist , wurde Eingerichtet).
Sridhar Sarnobat
4

Wenn Sie PHP haben :

php -r 'var_export(json_decode(`curl http://twitter.com/users/username.json`, 1));'

Zum Beispiel:
Wir haben eine Ressource, die json mit Länder-ISO-Codes versorgt: http://country.io/iso3.json, und wir können sie leicht in einer Shell mit Curl sehen:

curl http://country.io/iso3.json

aber es sieht nicht sehr praktisch und nicht lesbar aus, besser json analysieren und lesbare Struktur sehen:

php -r 'var_export(json_decode(`curl http://country.io/iso3.json`, 1));'

Dieser Code gibt Folgendes aus:

array (
  'BD' => 'BGD',
  'BE' => 'BEL',
  'BF' => 'BFA',
  'BG' => 'BGR',
  'BA' => 'BIH',
  'BB' => 'BRB',
  'WF' => 'WLF',
  'BL' => 'BLM',
  ...

Wenn Sie verschachtelte Arrays haben, sieht diese Ausgabe viel besser aus ...

Hoffe das wird hilfreich ...

V. Kovpak
quelle
4

Es gibt auch ein sehr einfaches, aber leistungsstarkes JSON CLI- Verarbeitungstool fx - https://github.com/antonmedv/fx

Beispiel für die JSON-Formatierung im Bash-Terminal

Beispiele

Verwenden Sie eine anonyme Funktion:

$ echo '{"key": "value"}' | fx "x => x.key"
value

Wenn Sie die anonyme Funktion param => ... nicht übergeben, wird der Code automatisch in eine anonyme Funktion umgewandelt. Mit diesem Schlüsselwort können Sie auf JSON zugreifen:

$ echo '[1,2,3]' | fx "this.map(x => x * 2)"
[2, 4, 6]

Oder verwenden Sie einfach auch die Punktsyntax:

$ echo '{"items": {"one": 1}}' | fx .items.one
1

Sie können eine beliebige Anzahl anonymer Funktionen zum Reduzieren von JSON übergeben:

$ echo '{"items": ["one", "two"]}' | fx "this.items" "this[1]"
two

Sie können vorhandenes JSON mit dem Spread-Operator aktualisieren:

$ echo '{"count": 0}' | fx "{...this, count: 1}"
{"count": 1}

Einfach nur JavaScript . Sie müssen keine neue Syntax lernen.


UPDATE 2018-11-06

fxhat jetzt interaktiven Modus ( ! )

https://github.com/antonmedv/fx

Anton Medwedew
quelle
7
Wenn Sie Ihre eigene Kreation fördern, müssen Sie dies explizit angeben. Siehe Wie man kein Spammer ist.
Tripleee
4

Dies ist eine weitere bash& pythonhybride Antwort. Ich habe diese Antwort gepostet, weil ich komplexere JSON-Ausgaben verarbeiten wollte, aber die Komplexität meiner Bash-Anwendung reduzieren wollte. Ich möchte das folgende JSON-Objekt von http://www.arcgis.com/sharing/rest/info?f=json in öffnen bash:

{
  "owningSystemUrl": "http://www.arcgis.com",
  "authInfo": {
    "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
    "isTokenBasedSecurity": true
  }
}

Im folgenden Beispiel habe ich meine eigene Implementierung jqund unquoteNutzung erstellt python. Sie werden feststellen, dass wir nach dem Importieren des Python-Objekts jsonin ein Python-Wörterbuch die Python-Syntax verwenden können, um im Wörterbuch zu navigieren. Um darin zu navigieren, lautet die Syntax:

  • data
  • data[ "authInfo" ]
  • data[ "authInfo" ][ "tokenServicesUrl" ]

Durch die Verwendung von Magie in Bash lassen wir dataden Python-Text rechts von den Daten weg und geben ihn nur an, d. H.

  • jq
  • jq '[ "authInfo" ]'
  • jq '[ "authInfo" ][ "tokenServicesUrl" ]'

Beachten Sie, ohne Parameter, jq als JSON-Prettifier fungiert. Mit Parametern können wir die Python-Syntax verwenden, um alles, was wir wollen, aus dem Wörterbuch zu extrahieren, einschließlich der Navigation in Unterwörterbüchern und Array-Elementen.

Hier ist ein Arbeitsbeispiel, das Folgendes demonstriert:

jq_py() {
cat <<EOF
import json, sys
data = json.load( sys.stdin )
print( json.dumps( data$1, indent = 4 ) )
EOF
}

jq() {
  python -c "$( jq_py "$1" )"
}

unquote_py() {
cat <<EOF
import json,sys
print( json.load( sys.stdin ) )
EOF
}

unquote() {
  python -c "$( unquote_py )"
}

curl http://www.arcgis.com/sharing/rest/info?f=json | tee arcgis.json
# {"owningSystemUrl":"https://www.arcgis.com","authInfo":{"tokenServicesUrl":"https://www.arcgis.com/sharing/rest/generateToken","isTokenBasedSecurity":true}}

cat arcgis.json | jq
# {
#     "owningSystemUrl": "https://www.arcgis.com",
#     "authInfo": {
#         "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
#         "isTokenBasedSecurity": true
#     }
# }

cat arcgis.json | jq '[ "authInfo" ]'
# {
#     "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
#     "isTokenBasedSecurity": true
# }

cat arcgis.json | jq '[ "authInfo" ][ "tokenServicesUrl" ]'
# "https://www.arcgis.com/sharing/rest/generateToken"

cat arcgis.json | jq '[ "authInfo" ][ "tokenServicesUrl" ]' | unquote
# https://www.arcgis.com/sharing/rest/generateToken
Stephen Quan
quelle
3

Ich habe dies getan und eine JSON-Antwort für einen bestimmten Wert wie folgt "analysiert":

curl $url | grep $var | awk '{print $2}' | sed s/\"//g 

Natürlich wäre $ url hier die Twitter-URL und $ var wäre "Text", um die Antwort für diese Variable zu erhalten.

Wirklich, ich denke, das einzige, was ich beim OP ausgelassen habe, ist grep für die Zeile mit der spezifischen Variablen, die er sucht. Awk schnappt sich den zweiten Punkt in der Zeile und mit sed entferne ich die Anführungszeichen.

Jemand, der schlauer ist als ich, könnte wahrscheinlich das ganze Denken mit awk oder grep machen.

Jetzt können Sie alles mit nur sed machen:

curl $url | sed '/text/!d' | sed s/\"text\"://g | sed s/\"//g | sed s/\ //g

also kein awk, kein grep ... Ich weiß nicht, warum ich vorher nicht daran gedacht habe. Hmmm...

Tonybaldwin
quelle
Eigentlich können Sie mit sed tun
Tonybaldwin
1
Die grep | awk | sedund sed | sed | sedPipelines sind verschwenderische Antimuster. Ihr letztes Beispiel kann leicht umgeschrieben werden, curl "$url" | sed '/text/!d;s/\"text\"://g;s/\"//g;s/\ //g'aber wie andere bereits betont haben, ist dies ein fehleranfälliger und spröder Ansatz, der überhaupt nicht empfohlen werden sollte.
Tripleee
Ich musste grep -oPz 'name \ ": \". *? \ "' Curloutput | sed 's / name \": / \ n / g' verwenden
Ferroao
3

Das Parsen von JSON ist in einem Shell-Skript schmerzhaft. Erstellen Sie mit einer geeigneteren Sprache ein Tool, das JSON-Attribute auf eine Weise extrahiert, die mit den Shell-Skriptkonventionen übereinstimmt. Sie können Ihr neues Tool verwenden, um das Problem mit der sofortigen Shell-Skripterstellung zu lösen und es dann für zukünftige Situationen zu Ihrem Kit hinzuzufügen.

Betrachten wir zum Beispiel ein Werkzeug jsonlookup so dass , wenn ich sage , jsonlookup access token ides wird das Attribut zurückgeben id im Attribut definiert Token innerhalb des Attribut definiert Zugriff von stdin, die vermutlich ist JSON - Daten. Wenn das Attribut nicht vorhanden ist, gibt das Tool nichts zurück (Exit-Status 1). Wenn die Analyse fehlschlägt, beenden Sie Status 2 und eine Nachricht an stderr. Wenn die Suche erfolgreich ist, druckt das Tool den Wert des Attributs.

Nachdem Sie ein Unix-Tool zum genauen Extrahieren von JSON-Werten erstellt haben, können Sie es problemlos in Shell-Skripten verwenden:

access_token=$(curl <some horrible crap> | jsonlookup access token id)

Jede Sprache reicht für die Implementierung von jsonlookup . Hier ist eine ziemlich prägnante Python-Version:

#!/usr/bin/python                                                               

import sys
import json

try: rep = json.loads(sys.stdin.read())
except:
    sys.stderr.write(sys.argv[0] + ": unable to parse JSON from stdin\n")
    sys.exit(2)
for key in sys.argv[1:]:
    if key not in rep:
        sys.exit(1)
    rep = rep[key]
print rep
mcnabicus
quelle
3

Ein Zweiliner, der Python verwendet. Dies funktioniert besonders gut, wenn Sie eine einzelne .sh-Datei schreiben und nicht von einer anderen .py-Datei abhängig sein möchten. Es nutzt auch die Verwendung von Rohren |. echo "{\"field\": \"value\"}"kann durch alles ersetzt werden, was einen json auf das stdout druckt.

echo "{\"field\": \"value\"}" | python -c 'import sys, json
print(json.load(sys.stdin)["field"])'
Adam Kurkiewicz
quelle
Die Frage war nicht auf der Suche nach einer Python-Lösung. Siehe auch die Kommentare.
Andrew Barber
3

Dies ist ein guter Anwendungsfall für Pythonpy :

curl 'http://twitter.com/users/username.json' | py 'json.load(sys.stdin)["name"]'
RussellStewart
quelle
Noch kürzeres Python-C-Modul hier :) schön.
m3nda