Question Analyser JSON avec des outils Unix


J'essaye d'analyser JSON retourné 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)?


532
2017-12-23 21:46


origine


Réponses:


Il y a un certain nombre d'outils spécialement conçus pour manipuler JSON à partir de la ligne de commande, et cela sera beaucoup plus facile et plus fiable qu'avec Awk, comme jq:

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

Vous pouvez également le faire avec des outils qui sont probablement déjà installés sur votre système, comme Python en utilisant json module, et ainsi éviter toute dépendance supplémentaire, tout en ayant l'avantage d'un analyseur JSON approprié. Supposons que vous souhaitiez utiliser UTF-8, dans lequel le JSON d'origine doit être codé et que les terminaux les plus modernes utilisent également:

Python 2:

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

Python 3:

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

Notes historiques

Cette réponse initialement recommandée jsawk, qui devrait encore fonctionner, mais est un peu plus encombrant à utiliser que jqet dépend de l'installation d'un interpréteur JavaScript autonome qui est moins commun qu'un interpréteur Python, donc les réponses ci-dessus sont probablement préférables:

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

Cette réponse utilisait aussi l'API Twitter à partir de la question, mais cette API ne fonctionne plus, rendant difficile la copie des exemples à tester, et la nouvelle API Twitter nécessite des clés API, donc je suis passé à l'API GitHub qui peut être utilisé facilement sans clé API. La première réponse à la question initiale serait:

curl 'http://twitter.com/users/username.json' | jq -r '.text'

612
2017-12-23 21:59



Pour extraire rapidement les valeurs d'une clé particulière, j'aime personnellement utiliser "grep -o", qui ne renvoie que la correspondance de la regex. Par exemple, pour obtenir le champ "texte" des tweets, quelque chose comme:

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

Cette regex est plus robuste que vous ne le pensez; par exemple, il traite très bien les chaînes ayant des virgules incorporées et des guillemets échappés à l'intérieur de celles-ci. Je pense qu'avec un peu plus de travail vous pourriez en faire un qui soit garanti pour extraire la valeur, si c'est atomique. (S'il a une imbrication, alors une regex ne peut pas le faire bien sûr.)

Et pour nettoyer davantage (tout en gardant l'échappement original 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 vrai analyseur JSON - oui, c'est essentiel pour la correction, mais

  1. Pour faire une analyse vraiment rapide, comme compter les valeurs pour vérifier les bogues de nettoyage des données ou obtenir une idée générale des données, il est plus rapide d'ajouter quelque chose sur la ligne de commande. Ouvrir un éditeur pour écrire un script est une source de distraction.
  2. grep -o est des ordres de grandeur plus rapide que la norme Python json bibliothèque, au moins en faisant cela pour les tweets (qui sont ~ 2 Ko chacun). Je ne suis pas sûr que ce soit juste parce que json est lent (je devrais comparer à yajl parfois); mais en principe, une regex devrait être plus rapide car son état fini et beaucoup plus optimisable, au lieu d'un analyseur qui doit supporter la récursivité, et dans ce cas, dépense beaucoup d'arbres de construction de CPU pour des structures qui ne vous intéressent pas. (Si quelqu'un écrivait un transducteur d'état fini qui effectuait une analyse JSON correcte (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églerait le 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; alors je passe à travers une enveloppe autour awk cela permet l'accès nommé aux colonnes. Ici: les scripts json2tsv et tsvawk. Donc, pour cet exemple, ce serait:

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

Cette approche n'aborde pas le n ° 2, est plus inefficace qu'un seul script Python, et elle est un peu cassante: elle force la normalisation des nouvelles lignes et des tabulations dans les valeurs de chaînes, pour être agréable avec la vue délimitée par champ / record du monde. Mais cela vous permet de rester sur la ligne de commande, avec plus de correction que grep -o.


219
2017-07-27 23:24



Sur la base que certaines des recommandations ici (en particulier dans les commentaires) ont suggéré l'utilisation de Python, j'ai été déçu de ne pas trouver un exemple.

Donc, voici une ligne pour obtenir une valeur unique à partir de certaines données JSON. Cela suppose que vous transportez les données (depuis quelque part) et devrait donc être utile dans un contexte de script.

echo '{"hostname":"test","domainname":"example.com"}' | python -c 'import json,sys;obj=json.load(sys.stdin);print obj[0]["hostname"]'

146
2017-12-06 13:05



Suivant l'exemple de MartinR et Boecko:

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

Cela vous donnera une sortie extrêmement conviviale. Très pratique:

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

116
2018-06-12 08:04



Tu pourrais juste Télécharger jq binaire pour votre plate-forme et courir (chmod +x jq):

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

Il extrait "name" attribut de l'objet json.

jq homepage dit que c'est comme sed pour les données JSON.


108
2018-05-30 13:59



Utilisation Le support JSON de Python au lieu d'utiliser awk!

Quelque chose comme ça:

curl -s http://twitter.com/users/username.json | \
    python -c "import json,sys;obj=json.load(sys.stdin);print obj['name'];"

85
2017-12-23 22:28



Utiliser Node.js

Si le système a  installé, il est possible d'utiliser le -p imprimer et -e Evaluez les drapeaux de script avec JSON.parse pour retirer toute valeur qui est nécessaire.

Un exemple simple utilisant la chaîne JSON { "foo": "bar" } et en tirant la valeur de "foo":

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

Parce que nous avons accès à cat et d'autres utilitaires, nous pouvons l'utiliser pour les fichiers:

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

Ou tout autre format tel qu'une URL contenant du JSON:

$ node -pe 'JSON.parse(process.argv[1]).name' "$(curl -s https://api.github.com/users/trevorsenior)"
Trevor Senior

74
2017-08-27 15:11



Vous avez demandé comment vous tirer dans le pied et je suis ici pour fournir les munitions:

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

Vous pourriez utiliser tr -d '{}' au lieu de sed. Mais les laisser complètement semble avoir l'effet désiré.

Si vous voulez enlever les cotations extérieures, dirigez le résultat de sed 's/\(^"\|"$\)//g'

Je pense que d'autres ont sonné l'alarme suffisante. Je serai là avec un téléphone portable pour appeler une ambulance. Feu quand prêt.


42
2017-12-24 00:08