web-dev-qa-db-fra.com

Analyser JSON avec les outils Unix

J'essaie d'analyser JSON renvoyé par une requête curl, comme suit:

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 puis-je imprimer un champ spécifique (désigné par le -v k=text)?

750
auser

Il existe un certain nombre d’outils spécialement conçus pour manipuler JSON à partir de la ligne de commande. Ils seront beaucoup plus faciles et plus fiables que de le faire avec Awk, tels que jq :

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

Vous pouvez également le faire avec des outils probablement déjà installés sur votre système, tels que Python à l'aide du module json , afin d'éviter toutes les dépendances supplémentaires, tout en bénéficiant d'un analyseur JSON approprié. Les éléments suivants supposent que vous souhaitez utiliser UTF-8, dans lequel le JSON d'origine doit être codé et qui est également utilisé par la plupart des terminaux modernes:

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 était à l'origine recommandée jsawk , qui devrait toujours fonctionner, mais qui est un peu plus fastidieuse à utiliser que jq et qui nécessite l'installation d'un interpréteur JavaScript autonome. est moins commun qu'un interprète Python, les réponses ci-dessus sont donc probablement préférables:

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

Cette réponse utilisait également à l'origine l'API Twitter de la question, mais cette API ne fonctionne plus, ce qui rend difficile la copie des exemples à tester. La nouvelle API Twitter requiert des clés API. Je suis donc passé à l'API GitHub, qui peut être utilisé facilement sans clés API. La première réponse à la question initiale serait:

curl 'http://Twitter.com/users/username.json' | jq -r '.text'
904
Brian Campbell

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 rationnelle. Par exemple, pour obtenir le champ "texte" dans les tweets, procédez comme suit:

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

Cette expression rationnelle est plus robuste que vous ne le pensez; Par exemple, il gère bien les chaînes comportant des virgules et des guillemets échappés. Je pense qu'avec un peu plus de travail, vous pourriez en créer un qui soit réellement garanti pour extraire la valeur, si c'est atomique. (S'il y a imbrication, alors une expression rationnelle ne peut pas le faire, bien sûr.)

Et pour plus de propreté (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 pour que vous utilisiez un véritable analyseur JSON - oui, c’est essentiel pour la correction, mais

  1. Pour effectuer une analyse très rapide, par exemple, compter les valeurs pour vérifier les bogues de nettoyage des données ou avoir une idée générale des données, il est plus rapide de cogner quelque chose sur la ligne de commande. Ouvrir un éditeur pour écrire un script est distrayant.
  2. grep -o est un ordre de grandeur plus rapide que la bibliothèque Python standard json, du moins pour les tweets (d'une taille d'environ 2 Ko chacun). Je ne sais pas si c'est simplement parce que json est lent (je devrais comparé à yajl de temps en temps); mais en principe, une expression rationnelle devrait être plus rapide car elle est dans un é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 de CPU pour des structures qui ne vous intéressent pas. (Si quelqu'un écrivait un transducteur à états finis qui effectuait une analyse JSON appropriée (avec une profondeur limitée), ce serait fantastique! Entre-temps, 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 n ° 1.

Une dernière solution, plus farfelue: j'ai écrit un script qui utilise Python json et extrait les clés souhaitées dans des colonnes séparées par des tabulations; puis je passe à travers un wrapper autour de awk qui permet un 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 ne concerne pas le n ° 2, elle est plus inefficace qu'un seul script Python et elle est un peu fragile: elle force la normalisation des nouvelles lignes et des tabulations dans les valeurs de chaîne, pour jouer à Nice avec le champ/enregistrement de awk vue délimitée du monde. Mais cela vous permet de rester sur la ligne de commande, avec plus de précision que grep -o.

263
Brendan OConnor

Étant donné 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. Cela suppose que vous pipiez les données (de 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["hostname"]'
162
paulkmoore

Suivant MartinR et Boecko:

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

Cela vous donnera une sortie extrêmement favorable à grep. Très pratique:

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

Vous pouvez juste télécharger jq binaire pour votre plate-forme et exécuter (chmod +x jq):

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

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

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

123
jfs

Utilisez 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'];"
95
martinr

Utiliser Node.js

Si le système est équipé de nœud , il est possible d'utiliser les impressions _-p_ et _-e_ avec les balises de script avec JSON.parse à retirer. toute valeur nécessaire.

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

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

Puisque 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 JSON:

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

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 pouvez utiliser tr -d '{}' au lieu de sed. Mais les laisser complètement à l’écart semble également avoir l’effet recherché.

Si vous souhaitez supprimer les guillemets extérieurs, transmettez le résultat de ce qui précè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.

55
Dennis Williamson

Utiliser Bash avec Python

Créez une fonction bash dans votre fichier .bash_rc

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

Ensuite

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

Voici la même fonction, mais avec vérification d'erreur.

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))";
}

Où $ # -ne 1 s'assure qu'au moins 1 entrée et -t 0 s'assurent que vous redirigez à partir d'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:

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

Si vous voulez être vraiment chic, vous pouvez assez imprimer les données:

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"
}
41
Joe Heyming

TickTick est un analyseur JSON écrit en bash (<250 lignes de code)

Voici l'extrait de l'auteur tiré de son article, Imaginez un monde où Bash prend en charge JSON :

#!/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
25
CoolAJ86

Analyse de JSON avec PHP CLI

Sans doute hors sujet, mais puisque la préséance règne, cette question reste incomplète sans mention de notre PHP fidèle et fidèle, ai-je raison?

En utilisant le même exemple de JSON, mais assignons-le à une variable pour réduire l'obscurité.

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

Maintenant, pour PHP bonté, utilisez file_get_contents et le php: // stdin wrapper de flux.

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

ou comme indiqué avec fgets et le flux déjà ouvert à la CLI constante STDIN .

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

nonJoy!

20
nickl-

Version native de Bash: fonctionne également bien avec les barres obliques inverses (\) et les guillemets (")

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
[email protected]
19
maikel

Version qui utilise Ruby et http://flori.github.com/json/

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

ou plus concement:

$ < file.json Ruby -r rubygems -r json -e "puts JSON.pretty_generate(JSON[STDIN.read]);"
12
boecko

Malheureusement, la réponse la plus votée qui utilise grep renvoie la correspondance complète qui ne fonctionnait pas dans mon scénario, mais si vous savez que le format JSON restera constant, vous pouvez utiliser lookbehind et lookahead pour extraire uniquement les valeurs souhaitées.

# 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
10
Daniel Sokolowski

Maintenant que Powershell est multi-plateforme, je pensais pouvoir me frayer un chemin, car je trouve cela assez intuitif et extrêmement simple.

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

ConvertFrom-Json convertit le JSON en objet personnalisé Powershell afin que vous puissiez facilement utiliser les propriétés à partir de ce point. Si vous ne vouliez que la propriété 'id' par exemple, procédez comme suit:

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

Si vous voulez invoquer tout cela depuis Bash, vous devez l'appeler ainsi:

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

Bien sûr, il existe un moyen pur Powershell de le faire sans boucle, qui serait:

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

Enfin, il y a aussi 'ConvertTo-Json' qui convertit un objet personnalisé en JSON aussi facilement. Voici un exemple:

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

Ce qui produirait Nice JSON comme ceci:

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

}

Certes, l’utilisation d’un shell Windows sous Unix est quelque peu sacrilège, mais Powershell est vraiment doué pour certaines choses, et l’analyse de JSON et de XML en sont quelques-unes. Ceci est la page GitHub pour la version multiplateforme https://github.com/PowerShell/PowerShell

7
user2233949

Si quelqu'un veut simplement extraire des valeurs 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 à l'aide d'expressions régulières bash basées sur le norme JSON :

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
}

Mises en garde: 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 appariée quelle que soit la profondeur dans le document JSON tant qu'elle porte exactement le même nom de clé.

En utilisant l'exemple de l'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
7
Helder Pereira

Je ne peux utiliser aucune des réponses ici. Pas de jq disponible, pas de tableaux Shell, pas de déclaration, pas de grep -P, pas de lookbehind et lookahead, pas de Python, pas de Perl, pas de Ruby, non - même pas Bash ... Les réponses restantes ne fonctionnent tout simplement pas bien. JavaScript me paraissait familier, mais la boîte de conserve dit Nescaffe - ce n'est donc pas une fin, aussi :) Même s'ils étaient disponibles, pour mon simple besoin - ils seraient excessifs et lents.

Cependant, il est extrêmement important pour moi d’obtenir de nombreuses variables à partir de la réponse au format json de mon modem. Je le fais dans un sh avec BusyBox très réduit à mes routeurs! Pas de 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!

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

Rappelez-vous que je n'ai pas de tableaux? J'ai dû affecter dans les données analysées par awk les 11 variables dont j'ai besoin dans un script Shell. Partout où je regardais, on disait que c'était une mission impossible. Pas de problème avec ça aussi.

Ma solution est simple. Ce code va: 1) analyser le fichier .json à partir de la question (en fait, j'ai emprunté un échantillon de données de travail de la réponse la plus votée) et choisir les données citées, plus 2) créer des variables Shell à partir de la commande awk assignant un Shell nommé libre noms de variables.

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"

Aucun problème avec les blancs à l'intérieur. Dans mon utilisation, la même commande analyse une longue sortie sur une seule ligne. Comme eval est utilisé, cette solution convient uniquement aux données sécurisées. Il est simple de l’adapter à la collecte de données non précisées. Pour un très grand nombre de variables, il est possible d’obtenir un gain de vitesse marginal en utilisant else if. Manque de tableau signifie évidemment: pas d'enregistrements multiples sans bidouillage supplémentaire. Mais là où des baies sont disponibles, l’adaptation de cette solution est une tâche simple.

@maikel sed answer fonctionne presque (mais je ne peux pas en parler). Pour mes données bien formatées - cela fonctionne. Pas tellement avec l'exemple utilisé ici (les citations manquantes le jettent au loin). 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 prenait 48,99 secondes et ma solution prenait 0,91 seconde! Pas juste? Effectuer une seule extraction de 9 variables: 0.51 vs. 0.02 sec.

6
Pila

Quelqu'un qui a aussi des fichiers XML, voudra peut-être regarder mon Xidel . C'est un processeur cli, sans dépendance JSONiq . (c'est-à-dire qu'il prend également en charge XQuery pour le traitement xml ou json)

L'exemple dans la question serait:

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

Ou avec ma propre syntaxe d'extension non standard:

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

Vous pouvez utiliser jshon :

curl 'http://Twitter.com/users/username.json' | jshon -e text
5
kev

Si vous avez php :

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

Par exemple:
nous avons une ressource qui fournit JSON avec les codes ISO des pays: http://country.io/iso3.json et nous pouvons facilement le voir dans un Shell avec curl:

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

mais cela ne semble pas très pratique, et pas lisible, mieux analyser json et voir la structure lisible:

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

Ce code imprimera quelque chose comme:

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

si vous avez des tableaux imbriqués, cette sortie aura une bien meilleure apparence ...

J'espère que cela vous aidera ...

4
Vladimir Kovpak

Il existe un moyen plus simple d'obtenir une propriété à partir d'une chaîne json. En utilisant un fichier package.json comme exemple, essayez ceci:

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

Nous utilisons process.env parce que cela récupère le contenu du fichier dans node.js sous forme de chaîne sans risque que des contenus malveillants échappent à leurs guillemets et soient analysés en tant que code.

4
Alexander Mills

Vous pouvez essayer quelque chose comme ça -

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

C'est encore une autre réponse hybride bash & python. J'ai posté cette réponse parce que je voulais traiter des sorties JSON plus complexes, tout en réduisant la complexité de mon application bash. Je veux ouvrir l'objet JSON suivant à partir de http://www.arcgis.com/sharing/rest/info?f=json dans bash:

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

Bien que cette approche augmente la complexité de la fonction Python, l'utilisation de bash devient plus simple:

function jsonGet {
  python -c 'import json,sys
o=json.load(sys.stdin)
k="'$1'"
if k != "":
  for a in k.split("."):
    if isinstance(o, dict):
      o=o[a] if a in o else ""
    Elif isinstance(o, list):
      if a == "length":
        o=str(len(o))
      Elif a == "join":
        o=",".join(o)
      else:
        o=o[int(a)]
    else:
      o=""
if isinstance(o, str) or isinstance(o, unicode):
  print o
else:
  print json.dumps(o)
'
}

curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet
curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet authInfo
curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet authInfo.tokenServicesUrl

La sortie du script ci-dessus est:

J'ai ajouté un support pour les tableaux, vous pouvez donc utiliser .length et, si la source est un tableau de chaînes, vous pouvez utiliser .join:

curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.length
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods.length
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods.23

Quelles sorties:

  • 1
  • [{"scale": 591657527.591555, "resolution": 156543.03392800014, "level": 0}, {"scale": 295828763.795777, "resolution": 78271.51696399994, "level": 1}, {"scale": 1}, {"scale": 1458141.897889, "resolution ": 39135.75848200009," niveau ": 2}, {" échelle ": 73957190.948944," résolution ": 19567.87924099992," niveau ": 3}, {" échelle ": 36978595.474472," résolution ": 1 973.93962049996," niveau ": 4} , {"échelle": 18489297.737236, "résolution": 4891.96981024998, "niveau": 5}, {"échelle": 9244648.868618, "résolution": 2445.98490512499, "niveau": 6}, {"échelle": 6}, {"échelle": 4622324.434309, résolution ": 1222.992452562495," niveau ": 7}, {" échelle ": 2311162.217155," résolution ": 611.4962262813797," niveau ": 8}, {" échelle ": 1155581.108577," résolution ": 305.74811314055756," niveau ": 9} , {"scale": 577790.554289, "resolution": 152.87405657041106, "level": 10}, {"scale": 288895.277144, "resolution": 76.43702828507324, "level": 11}, {"scale": 288895.277144, "resolution": 76,43702828507324, level ": 11}, {" scale ": 144447.638572," resolution ": 38.21851414253662," niveau ": 12}, {" échelle ": 72223.819286," résolution ": 19.1092570712683 1, "niveau": 13}, {"échelle": 36111.909643, "résolution": 9.554628535634155, "niveau": 14}, {"échelle": 18055.954822, "résolution": 4.7773142679493737, "niveau": 15}, { "scale": 9027.977411, "resolution": 2.388657133974685, "level": 16}, {"scale": 4513.988705, "resolution": 1.1943285668550503, "level": 17}, {"scale": 4513.988705, "resolution": 1.1943285668550503, "level": 17}, {"scale": 2256.994353, "résolution": 0.5971642835598172, "niveau": 18}, {"échelle": 1128.497176, "résolution": 0.29858214164761665, "niveau": 19}, {"échelle": 564.248588, "résolution": 0.14929107082380833, "niveau": 20}, {} "scale": 282.124294, "resolution": 0.07464553541190416, "level": 21}, {"scale": 141.062147, "resolution": 0.03732276770595208, "level": 22}, {"scale": 141.062147, "resolution": 0.03732276770595208, "level": 22}, {"scale": 70.5310735, "résolution": 0.01866138385297604, "level": 23}]
  • 24
  • {"scale": 70.5310735, "resolution": 0.01866138385297604, "level": 23}
4
Stephen Quan

voici une façon de le faire avec awk

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
        }
    }
}'
4
ghostdog74

Pour une analyse JSON plus complexe, je suggère d'utiliser le module python jsonpath (par Stefan Goessner) -

  1. Installez-le -

Sudo easy_install -U jsonpath

  1. Utilise le -

Exemple file.json (de 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
    }
  }
}

Analyser (extraire tous les titres de livres avec un prix <10) -

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

Va sortir -

Sayings of the Century
Moby Dick

REMARQUE: La ligne de commande ci-dessus n'inclut pas la vérification d'erreur. pour une solution complète avec vérification des erreurs, vous devez créer un petit script python, et envelopper le code avec try-except.

4
shlomosh

Si pip est disponible sur le système, alors:

$ pip install json-query

Exemples d'utilisation:

$ curl -s http://0/file.json | json-query
{
    "key":"value"    
}

$ curl -s http://0/file.json | json-query my.key
value

$ curl -s http://0/file.json | json-query my.keys.
key_1
key_2
key_3

$ curl -s http://0/file.json | json-query my.keys.2
value_2
3
Alexey Dubkov

Il existe également un outil de traitement très simple mais puissant JSON CLI fx - https://github.com/antonmedv/fx

Example of JSON formatting in Bash terminal

Exemples

Utiliser une fonction anonyme:

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

Si vous ne transmettez pas la fonction anonyme param => ..., le code sera automatiquement transformé en fonction anonyme. Et vous pouvez accéder à JSON avec ce mot clé:

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

Ou utilisez simplement la syntaxe à points aussi:

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

Vous pouvez transmettre autant de fonctions anonymes que vous le souhaitez pour réduire JSON:

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

Vous pouvez mettre à jour le code JSON existant à l'aide de l'opérateur de propagation:

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

Simplement JavaScript . Pas besoin d'apprendre une nouvelle syntaxe.


UPDATE 2018-11-06

fx a maintenant le mode interactif (! )

https://github.com/antonmedv/fx

3
Anton Medvedev

L'analyse de JSON est pénible dans un script Shell. Avec un langage plus approprié, créez un outil qui extrait les attributs JSON conformément aux conventions de script du shell. Vous pouvez utiliser votre nouvel outil pour résoudre le problème de script immédiat du shell, puis l'ajouter à votre kit pour les situations futures.

Par exemple, considérons un outil jsonlookup tel que si je dis jsonlookup access token id, il retournera l'attribut id défini dans l'attribut jeton défini dans l'attribut access à partir de stdin, ce qui est vraisemblablement une donnée JSON. Si l'attribut n'existe pas, l'outil ne renvoie rien (statut de sortie 1). Si l'analyse échoue, quittez le statut 2 et envoyez un message à stderr. Si la recherche aboutit, 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 l’utiliser facilement dans des scripts Shell:

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

Toute langue fera pour la mise en œuvre de jsonlookup. Voici une version assez concise de la version python:

#!/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
3
mcnabicus

Une doublure 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 du tuyau |. echo "{\"field\": \"value\"}" peut être remplacé par tout ce qui imprime un JSON sur la sortie standard.

echo "{\"field\": \"value\"}" | python -c 'import sys, json
print(json.load(sys.stdin)["field"])'
3
Adam Kurkiewicz

C'est un bon cas d'utilisation pour python :

curl 'http://Twitter.com/users/username.json' | py 'json.load(sys.stdin)["name"]'
3
RussellStewart

je l'ai utilisé pour extraire la durée de la vidéo de la sortie de ffprobe json:

MOVIE_INFO=`ffprobe "path/to/movie.mp4"  -show_streams -show_format -print_format json -v quiet` 
MOVIE_SECONDS=`echo "$MOVIE_INFO"|grep -w \"duration\" |tail -1 | cut -d\" -f4 |cut -d \. -f 1`

il peut être utilisé pour extraire la valeur de n'importe quel json:

value=`echo "$jsondata"|grep -w \"key_name\" |tail -1 | cut -d\" -f4
2
Ehsan Chavoshi

Voici une bonne référence . Dans ce cas:

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++) { where = match(a[i], /\"text\"/); if(where) {print a[i]} }  }'
2
Max Barrass

Il me fallait quelque chose dans BASH qui soit court et qui fonctionnerait sans dépendances autres que Vanilla Linux LSB et Mac OS pour python 2.7 & 3 et gérer les erreurs, par exemple. signalerait les erreurs d'analyse json et les erreurs de propriétés manquantes sans spewing python exceptions:

json-extract () {
  if [[ "$1" == "" || "$1" == "-h" || "$1" == "-?" || "$1" == "--help" ]] ; then
    echo 'Extract top level property value from json document'
    echo '  Usage: json-extract <property> [ <file-path> ]'
    echo '  Example 1: json-extract status /tmp/response.json'
    echo '  Example 2: echo $JSON_STRING | json-extract-file status'
    echo '  Status codes: 0 - success, 1 - json parse error, 2 - property missing'
  else
    python -c $'import sys, json;\ntry: obj = json.load(open(sys.argv[2])); \nexcept: sys.exit(1)\ntry: print(obj[sys.argv[1]])\nexcept: sys.exit(2)' "$1" "${2:-/dev/stdin}"
  fi
}
2
Mike

Vous pouvez utiliser bashJson

C'est un wrapper pour le module json de Python et peut gérer des données json complexes.

Considérons cette exmaple donnée JSON du fichier test.json

 {
 "name": "Outil de test", 
 "auteur": "hack4mer", 
 "supported_os": {
 "osx ": {
" foo ":" bar ", 
" min_version ": 10.12, 
" testée sur ", [10.1,10.13] 
}, 
 "ubuntu": {
 "min_version": 14.04, 
 "testée sur": 16.04 
} 
} 

Les commandes suivantes lisent les données de cet exemple de fichier json

./bashjson.sh test.json name

Prints: Outil de test

./bashjson.sh test.json supported_os osx foo

Impressions: bar

./bashjson.sh test.json supported_os osx tested_on

Impressions: [10.1,10.13]

1
hack4mer

Je l'ai fait en "analysant" une réponse JSON pour une valeur particulière, comme suit:

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

Clairement, $ url serait ici 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 faisais avec le PO, c’est grep pour la ligne avec la variable spécifique qu’il recherche. Awk attrape le deuxième article sur la ligne et avec sed je dépouille les guillemets.

Quelqu'un plus intelligent que moi pourrait probablement penser à tout avec awk ou grep.

Maintenant, vous pouvez tout faire avec simplement sed:

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

donc, pas de mal, pas de grep ... Je ne sais pas pourquoi je n'y avais pas pensé auparavant. Hmmm ...

1
tonybaldwin

Niet est un outil qui vous aide à extraire les données d'un fichier json ou yaml directement dans votre CLI Shell/bash.

$ pip install niet

Considérons un fichier json nommé project.json avec le contenu suivant:

{
  project: {
    meta: {
      name: project-sample
    }
}

Vous pouvez utiliser niet comme ceci:

$ PROJECT_NAME=$(niet project.json project.meta.name)
$ echo ${PROJECT_NAME}
project-sample
1
Herve