J'essaie d'analyser le JSON renvoyé d'une demande de boucle, comme ceci:
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]}'
Ce qui précède divise le JSON en champs, par exemple:
% ...
"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
% ...
Comment imprimer un champ spécifique (indiqué par le -v k=text
)?
grep -Po '"'"version"'"\s*:\s*"\K([^"]*)' package.json
. Cela résout la tâche facilement et uniquement avec grep et fonctionne parfaitement pour les JSON simples. Pour les JSON complexes, vous devez utiliser un analyseur approprié.Réponses:
Il existe un certain nombre d'outils spécialement conçus pour manipuler JSON à partir de la ligne de commande, et seront beaucoup plus faciles et plus fiables que de le faire avec Awk, tels que
jq
:Vous pouvez également le faire avec des outils qui sont probablement déjà installés sur votre système, comme Python en utilisant le
json
module , et ainsi éviter toute dépendance supplémentaire, tout en bénéficiant d'un analyseur JSON approprié. Ce qui suit suppose que vous souhaitez utiliser UTF-8, dans lequel le JSON d'origine doit être codé et c'est ce que la plupart des terminaux modernes utilisent également:Python 3:
Python 2:
Notes historiques
Cette réponse recommandait à l'origine jsawk , qui devrait toujours fonctionner, mais est un peu plus lourd à utiliser que
jq
, et dépend d'un interpréteur JavaScript autonome en cours d'installation qui est moins courant qu'un interprète Python, donc les réponses ci-dessus sont probablement préférables:Cette réponse a également utilisé à l'origine l'API Twitter de la question, mais cette API ne fonctionne plus, ce qui rend difficile la copie des exemples à tester, et la nouvelle API Twitter nécessite des clés d'API, j'ai donc basculé vers l'utilisation de l'API GitHub qui peut être utilisé facilement sans clés API. La première réponse à la question d'origine serait:
la source
print
instruction sera toujours codée en ASCII car vous utilisez Python dans un canal. InsérezPYTHONIOENCODING=<desired codec>
dans la commande pour définir un codage de sortie différent, adapté à votre terminal. En Python 3, la valeur par défaut est UTF-8 dans ce cas (en utilisant laprint()
fonction ).curl -s
est équivalent àcurl --silent
, tandis quejq -r
signifiejq --raw-output
ie sans guillemets.Pour extraire rapidement les valeurs d'une clé particulière, j'aime personnellement utiliser "grep -o", qui ne renvoie que la correspondance de l'expression régulière. Par exemple, pour obtenir le champ "texte" des tweets, quelque chose comme:
Cette expression régulière est plus robuste que vous ne le pensez; par exemple, il traite très bien les chaînes ayant des virgules intégrées et des guillemets échappés à l'intérieur. Je pense qu'avec un peu plus de travail, vous pourriez en faire un qui soit garanti d'extraire la valeur, s'il est atomique. (S'il a une imbrication, un regex ne peut pas le faire bien sûr.)
Et pour nettoyer plus (mais en gardant Escaping originale de la chaîne) , vous pouvez utiliser quelque chose comme:
| perl -pe 's/"text"://; s/^"//; s/",$//'
. (Je l'ai fait pour cette analyse .)Pour tous les ennemis qui insistent sur le fait que vous devriez utiliser un véritable analyseur JSON - oui, c'est essentiel pour l'exactitude, mais
grep -o
est un ordre de grandeur plus rapide que lajson
bibliothèque standard Python , du moins lors de cette opération pour les tweets (qui font environ 2 Ko chacun). Je ne sais pas si c'est juste parce quejson
c'est lent (je devrais comparer avec yajl un jour); mais en principe, une expression régulière devrait être plus rapide car elle est à l'état fini et beaucoup plus optimisable, au lieu d'un analyseur qui doit prendre en charge la récursivité, et dans ce cas, dépense beaucoup d'arbres de construction CPU pour les structures qui ne vous intéressent pas. (Si quelqu'un écrivait un transducteur à états finis qui effectuait une analyse JSON appropriée (limitée en profondeur), ce serait fantastique! En attendant, nous avons "grep -o".)Pour écrire du code maintenable, j'utilise toujours une vraie bibliothèque d'analyse. Je n'ai pas essayé jsawk , mais si cela fonctionne bien, cela répondrait au point # 1.
Une dernière solution, plus farfelue: j'ai écrit un script qui utilise Python
json
et extrait les clés que vous voulez, dans des colonnes séparées par des tabulations; puis je passe à travers un wrapperawk
qui permet un accès nommé aux colonnes. Ici: les scripts json2tsv et tsvawk . Donc pour cet exemple ce serait:Cette approche ne prend pas en compte le # 2, est plus inefficace qu'un seul script Python, et elle est un peu fragile: elle force la normalisation des sauts de ligne et des tabulations dans les valeurs de chaîne, pour bien jouer avec la vue du monde délimitée par les enregistrements / champs d'AWK. Mais cela vous permet de rester sur la ligne de commande, avec plus d'exactitude que
grep -o
.la source
grep -Po '"text":(\d*?,|.*?[^\\]",)'
jq .name
fonctionne sur la ligne de commande et ne nécessite pas "d'ouvrir un éditeur pour écrire un script". 2. Peu importe la vitesse à laquelle votre expression| grep -Po '"text":.*?[^\\]",'|awk -F':' '{print $2}'
-P
option soit manquante. Je l' ai testé sur OSX 10.11.5 etgrep --version
étaitgrep (BSD grep) 2.5.1-FreeBSD
. Je l'ai fait fonctionner avec l'option "regex étendu" sur OSX. La commande d'en haut seraitgrep -Eo '"text":.*?[^\\]",' tweets.json
.Sur la base que certaines des recommandations ici (en particulier dans les commentaires) suggéraient l'utilisation de Python, j'ai été déçu de ne pas trouver d'exemple.
Donc, voici une ligne pour obtenir une valeur unique à partir de certaines données JSON. Il suppose que vous canalisez les données (de quelque part) et devrait donc être utile dans un contexte de script.
la source
pythonpy
( github.com/russell91/pythonpy est presque toujours une meilleure alternative àpython -c
, bien qu'il doive être installé avec pip. redirigez simplement le json verspy --ji -x 'x[0]["hostname"]'
. Si vous ne vouliez pas utiliser le support json_input intégré, vous pourriez toujours obtenir ceux-ci importent automatiquement en tant quepy 'json.loads(sys.stdin)[0]["hostname"]'
jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); print($1)"; }
pour que je puisse écrire:curl ...... | jsonq 'json.dumps([key["token"] for key in obj], indent=2)'
& plus de choses effrayantes similaires ... Btw,obj[0]
semble inutile, il semble que çaobj
fonctionne bien dans les cas par défaut (?).jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); sys.stdout.write(json.dumps($1))"; }
obj[0]
provoque une erreur lors de l'analyse{ "port":5555 }
. Fonctionne bien après le retrait[0]
.Suivant l'exemple de MartinR et Boecko:
Cela vous donnera une sortie extrêmement conviviale pour grep. Très pratique:
la source
| grep field
. Merci!jq
n'est généralement pas installé alors que python l'est. De plus, une fois que vous êtes en Python, vous pourriez aussi bien faire tout le chemin et l'analyser avecimport json...
Vous pouvez simplement télécharger le
jq
binaire pour votre plate - forme et exécuter (chmod +x jq
):Il extrait l'
"name"
attribut de l'objet json.jq
la page d'accueil dit que c'est commesed
pour les données JSON.la source
jq
est un outil incroyable.curl -s https://api.example.com/jobs | jq '.jobs[] | {id, o: .owner.username, dateCreated, s: .status.state}'
Utilisation de Node.js
Si le système a nœudinstallé, il est possible d'utiliser les indicateurs de script
-p
print et-e
evaulate avecJSON.parse
pour extraire toute valeur nécessaire.Un exemple simple utilisant la chaîne JSON
{ "foo": "bar" }
et extrayant la valeur de "foo":Étant donné que nous avons accès à d'
cat
autres utilitaires, nous pouvons les utiliser pour les fichiers:Ou tout autre format tel qu'une URL contenant du JSON:
la source
node -p -e 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'
curl -s https://api.github.com/users/trevorsenior | node -pe "JSON.parse(require('fs').readFileSync('/dev/stdin').toString()).name"
cat package.json | node -pe 'JSON.parse(fs.readFileSync(0)).version'
Utilisez le support JSON de Python au lieu d'utiliser awk!
Quelque chose comme ça:
la source
json.load(sys.stdin)['"key']"
comme exemple comme:curl -sL httpbin.org/ip | python -c "import json,sys; print json.load(sys.stdin)['origin']"
.Vous avez demandé comment vous tirer une balle dans le pied et je suis ici pour fournir les munitions:
Vous pouvez utiliser à la
tr -d '{}'
place desed
. Mais les laisser complètement de côté semble également avoir l'effet souhaité.Si vous souhaitez supprimer les guillemets extérieurs, canalisez le résultat de ce qui précède à travers
sed 's/\(^"\|"$\)//g'
Je pense que d'autres ont suffisamment sonné l'alarme. Je serai avec un téléphone portable pour appeler une ambulance. Tirez quand vous êtes prêt.
la source
Utiliser Bash avec Python
Créez une fonction bash dans votre fichier .bash_rc
alors
Voici la même fonction, mais avec vérification des erreurs.
Où $ # -ne 1 garantit au moins 1 entrée et -t 0 vous assure que vous redirigez depuis un tube.
La bonne chose à propos de cette implémentation est que vous pouvez accéder aux valeurs json imbriquées et obtenir json en retour! =)
Exemple:
Si vous voulez être vraiment fantaisiste, vous pouvez imprimer les données:
la source
curl http://foo | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["environment"][0]["name"]'
sys.stdout.write()
si vous voulez qu'il fonctionne avec les deux python 2 et 3.getJsonVal() { py -x "json.dumps(json.loads(x)$1, sort_keys=True, indent=4)"; }
TickTick est un analyseur JSON écrit en bash (<250 lignes de code)
Voici l'extrait de l'auteur de son article, Imaginez un monde où Bash prend en charge JSON :
la source
Analyser JSON avec PHP CLI
Sans doute hors sujet, mais puisque la priorité règne, cette question reste incomplète sans mentionner notre PHP fidèle et fidèle, ai-je raison?
En utilisant le même exemple JSON mais permet de l'affecter à une variable pour réduire l'obscurité.
Maintenant pour la qualité PHP, en utilisant file_get_contents et le wrapper de flux php: // stdin .
ou comme indiqué en utilisant fgets et le flux déjà ouvert à la constante CLI STDIN .
nJoy!
la source
$argn
au lieu defgets(STDIN)
$argn
fonctionne avec l'indicateur -E ou -R et seulement si le contenu JSON est sur une seule ligne ...Version native de Bash: fonctionne également bien avec les barres obliques inverses (\) et les guillemets (")
la source
Version qui utilise Ruby et http://flori.github.com/json/
ou plus concis:
la source
;
n'est pas requise dans Ruby (elle n'est utilisée que pour concaténer des instructions qui se trouveraient normalement sur des lignes distinctes en une seule ligne).Malheureusement , la réponse qui a voté top utilisations
grep
renvoie le plein match qui n'a pas fonctionné dans mon scénario, mais si vous connaissez le format JSON reste constante , vous pouvez utiliser lookbehind et préanalyse pour extraire uniquement les valeurs souhaitées.la source
Si quelqu'un veut simplement extraire des valeurs à partir d'objets JSON simples sans avoir besoin de structures imbriquées, il est possible d'utiliser des expressions régulières sans même quitter le bash.
Voici une fonction que j'ai définie en utilisant des expressions régulières bash basées sur la norme JSON :
Avertissements: les objets et les tableaux ne sont pas pris en charge en tant que valeur, mais tous les autres types de valeur définis dans la norme sont pris en charge. En outre, une paire sera mise en correspondance, quelle que soit la profondeur dans le document JSON, tant qu'elle a exactement le même nom de clé.
En utilisant l'exemple d'OP:
la source
Il existe un moyen plus simple d'obtenir une propriété à partir d'une chaîne json. En utilisant un
package.json
fichier comme exemple, essayez ceci:Nous utilisons
process.env
car cela obtient le contenu du fichier dans node.js sous forme de chaîne sans aucun risque de contenu malveillant échappant à leur citation et analysé en tant que code.la source
require()
peut réellement exécuter du code étranger, JSON.parse ne peut pas.JSON.parse()
et oui, vous êtes sûr sans ambiguïté ... mais ici, le runtime JSON reçoit le contenu (non approuvé) en bande avec le code (de confiance).JSON.parse()
, vous êtes également en sécurité, mais cela ne se produit pas non plus ici.JSON.parse()
, dans le code . Vous en supposant que la mise des accents graves littérales gardera le contenu littéral, mais c'est une hypothèse tout à fait dangereuse, parce que les apostrophes inverses littérales peuvent exister dans le contenu du fichier (et donc la variable), et peut ainsi mettre fin à la citation et entrer dans un contexte non coté où le les valeurs sont exécutées sous forme de code.Maintenant que Powershell est multiplateforme, je pensais que j'allais me lancer là-bas, car je le trouve assez intuitif et extrêmement simple.
ConvertFrom-Json convertit le JSON en un objet personnalisé Powershell, de sorte que vous pouvez facilement travailler avec les propriétés à partir de ce point. Si vous vouliez seulement la propriété 'id' par exemple, vous feriez juste ceci:
Si vous vouliez invoquer le tout depuis Bash, alors vous devriez l'appeler comme ceci:
Bien sûr, il existe une manière Powershell pure de le faire sans boucle, qui serait:
Enfin, il existe également 'ConvertTo-Json' qui convertit tout aussi facilement un objet personnalisé en JSON. Voici un exemple:
Ce qui produirait un joli JSON comme celui-ci:
}
Certes, l'utilisation d'un shell Windows sur Unix est quelque peu sacrilège, mais Powershell est vraiment bon dans certaines choses, et l'analyse JSON et XML en sont quelques-unes. Ceci est la page GitHub pour la version multiplateforme https://github.com/PowerShell/PowerShell
la source
Quelqu'un qui a également des fichiers xml, voudra peut-être regarder mon Xidel . Il s'agit d'un processeur JSONiq sans cli et sans dépendance . (c'est-à-dire qu'il prend également en charge XQuery pour le traitement xml ou json)
L'exemple dans la question serait:
Ou avec ma propre syntaxe d'extension non standard:
la source
xidel -s https://api.github.com/users/lambda -e 'name'
(ou-e '$json/name'
, ou-e '($json).name'
).Je ne peux utiliser aucune des réponses ici. Pas de jq disponible, pas de tableaux de shell, pas de déclaration, pas de grep -P, pas de lookbehind et lookahead, pas de Python, pas de Perl, pas de Ruby, non - pas même Bash ... Les réponses restantes ne fonctionnent tout simplement pas bien. JavaScript semblait familier, mais l'étain dit Nescaffe - donc c'est non plus :) Même si disponible, pour mon simple besoin - ils seraient exagérés et lents.
Pourtant, il est extrêmement important pour moi d'obtenir de nombreuses variables de la réponse au format json de mon modem. Je le fais dans un sh avec BusyBox très coupé vers le bas à mes routeurs! Aucun problème en utilisant awk seul: il suffit de définir des délimiteurs et de lire les données. Pour une seule variable, c'est tout!
Rappelez-vous que je n'ai pas de tableaux? J'ai dû affecter dans les données analysées awk aux 11 variables dont j'ai besoin dans un script shell. Partout où je regardais, c'était une mission impossible. Pas de problème avec ça aussi.
Ma solution est simple. Ce code va: 1) analyser le fichier .json de la question (en fait, j'ai emprunté un échantillon de données de travail à la réponse la plus votée) et sélectionner les données citées, plus 2) créer des variables de shell à l'intérieur de l'awk en attribuant un shell nommé gratuit noms de variables.
Aucun problème avec les blancs à l'intérieur. Dans mon utilisation, la même commande analyse une sortie longue ligne unique. Comme eval est utilisé, cette solution convient uniquement aux données fiables. Il est simple de l'adapter à la collecte de données non cotées. Pour un grand nombre de variables, un gain de vitesse marginal peut être obtenu en utilisant else if. Manque de tableau signifie évidemment: pas d'enregistrements multiples sans bidouilles supplémentaires. Mais là où des baies sont disponibles, l'adaptation de cette solution est une tâche simple.
@maikel sed répond presque fonctionne (mais je ne peux pas en parler). Pour mes données bien formatées - cela fonctionne. Pas tellement avec l'exemple utilisé ici (les guillemets manquants le jettent). C'est compliqué et difficile à modifier. De plus, je n'aime pas avoir à faire 11 appels pour extraire 11 variables. Pourquoi? J'ai chronométré 100 boucles en extrayant 9 variables: la fonction sed a pris 48,99 secondes et ma solution a pris 0,91 secondes! Pas juste? Faire une seule extraction de 9 variables: 0,51 contre 0,02 s.
la source
Vous pouvez essayer quelque chose comme ça -
la source
Vous pouvez utiliser
jshon
:la source
voici une façon de le faire avec awk
la source
Pour une analyse JSON plus complexe, je suggère d'utiliser le module python jsonpath (par Stefan Goessner) -
sudo easy_install -U jsonpath
Exemple de fichier.json (depuis http://goessner.net/articles/JsonPath ) -
Analyser (extraire tous les titres de livres avec un prix <10) -
Sortira -
REMARQUE: la ligne de commande ci-dessus n'inclut pas la vérification des erreurs. pour une solution complète avec vérification des erreurs, vous devez créer un petit script python et encapsuler le code avec try-except.
la source
jsonpath
donc installé à lajsonpath_rw
place, alors voici quelque chose de similaire que vous pouvez essayer si ce qui précède ne fonctionne pas: 1)/usr/bin/python -m pip install jsonpath-rw
2)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;"
(J'ai utilisé le chemin complet vers le binaire python parce que j'avais des problèmes avec plusieurs pythons installée).Si vous avez php :
Par exemple:
nous avons une ressource qui fournit à json les codes iso des pays: http://country.io/iso3.json et nous pouvons facilement le voir dans un shell avec curl:
mais cela ne semble pas très pratique et pas lisible, mieux analyser json et voir la structure lisible:
Ce code imprimera quelque chose comme:
si vous avez des tableaux imbriqués, cette sortie sera bien meilleure ...
J'espère que cela vous sera utile ...
la source
Il existe également un outil de traitement JSON CLI très simple mais puissant fx - https://github.com/antonmedv/fx
Exemples
Utilisez une fonction anonyme:
Si vous ne transmettez pas la fonction anonyme param => ..., le code sera automatiquement transformé en fonction anonyme. Et vous pouvez accéder à JSON par ce mot-clé:
Ou utilisez également la syntaxe par points:
Vous pouvez transmettre un nombre illimité de fonctions anonymes pour réduire JSON:
Vous pouvez mettre à jour le JSON existant à l'aide de l'opérateur d'étalement:
Tout simplement JavaScript . Pas besoin d'apprendre une nouvelle syntaxe.
MISE À JOUR 2018-11-06
fx
a maintenant le mode interactif ( ! )https://github.com/antonmedv/fx
la source
Ceci est encore une autre
bash
etpython
réponse hybride. J'ai posté cette réponse parce que je voulais traiter une sortie JSON plus complexe, mais en réduisant la complexité de mon application bash. Je souhaite ouvrir l'objet JSON suivant à partir de http://www.arcgis.com/sharing/rest/info?f=json dansbash
:Dans l'exemple suivant, j'ai créé ma propre implémentation
jq
etunquote
optimisationpython
. Vous remarquerez qu'une fois que nous importons l'objet python depuisjson
dans un dictionnaire python, nous pouvons utiliser la syntaxe python pour naviguer dans le dictionnaire. Pour naviguer dans ce qui précède, la syntaxe est la suivante:data
data[ "authInfo" ]
data[ "authInfo" ][ "tokenServicesUrl" ]
En utilisant la magie dans bash, nous omettons
data
et ne fournissons que le texte python à droite des données, c'est-à-direjq
jq '[ "authInfo" ]'
jq '[ "authInfo" ][ "tokenServicesUrl" ]'
Notez, sans paramètres,
jq
agit comme un prettifier JSON. Avec les paramètres, nous pouvons utiliser la syntaxe python pour extraire tout ce que nous voulons du dictionnaire, y compris la navigation dans les sous-répertoires et les éléments de tableau.Voici un exemple de travail qui illustre ce qui précède:
la source
J'ai fait cela, "analysant" une réponse json pour une valeur particulière, comme suit:
Clairement, $ url ici serait l'url de twitter, et $ var serait "text" pour obtenir la réponse pour cette var.
Vraiment, je pense que la seule chose que je fais l'OP a laissé de côté est grep pour la ligne avec la variable spécifique qu'il cherche. Awk saisit le deuxième élément de la ligne et avec sed, je supprime les guillemets.
Quelqu'un plus intelligent que moi pourrait probablement penser le tout avec awk ou grep.
Maintenant, vous pouvez tout faire avec simplement sed:
donc pas d'awk, pas de grep ... Je ne sais pas pourquoi je n'y avais pas pensé avant. Hmmm ...
la source
grep | awk | sed
etsed | sed | sed
sont des antipatterns inutiles. Votre dernier exemple peut facilement être réécrit,curl "$url" | sed '/text/!d;s/\"text\"://g;s/\"//g;s/\ //g'
mais comme d'autres l'ont souligné, c'est une approche sujette aux erreurs et fragile qui ne devrait pas être recommandée en premier lieu.L'analyse JSON est pénible dans un script shell. Avec un langage plus approprié, créez un outil qui extrait les attributs JSON d'une manière cohérente avec les conventions de script shell. Vous pouvez utiliser votre nouvel outil pour résoudre le problème immédiat de script shell et l'ajouter ensuite à votre kit pour des situations futures.
Par exemple, considérons un outil jsonlookup tel que si je dis
jsonlookup access token id
qu'il renverra l' ID d' attribut défini dans le jeton d' attribut défini dans l' accès d' attribut de stdin, qui est vraisemblablement des données JSON. Si l'attribut n'existe pas, l'outil ne renvoie rien (quitter le statut 1). Si l'analyse échoue, quittez l'état 2 et un message à stderr. Si la recherche réussit, l'outil imprime la valeur de l'attribut.Après avoir créé un outil Unix dans le but précis d'extraire des valeurs JSON, vous pouvez facilement l'utiliser dans des scripts shell:
N'importe quel langage fera l'affaire pour l'implémentation de jsonlookup . Voici une version python assez concise:
la source
Un deux lignes qui utilise du python. Cela fonctionne particulièrement bien si vous écrivez un seul fichier .sh et que vous ne voulez pas dépendre d'un autre fichier .py. Il tire également parti de l'utilisation des tuyaux
|
.echo "{\"field\": \"value\"}"
peut être remplacé par tout ce qui imprime un json sur la sortie standard.la source
C'est un bon cas d' utilisation pour pythonpy :
la source