Analizar JSON con herramientas Unix


Estoy tratando de analizar JSON devuelto de una solicitud curl, así:

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]}'

Lo anterior divide el JSON en campos, por ejemplo:

% ...
"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
% ...

¿Cómo puedo imprimir un campo específico (denotado por el -v k=text)?

Author: codeforester, 2009-12-24

30 answers

Hay una serie de herramientas diseñadas específicamente para el propósito de manipular JSON desde la línea de comandos, y será mucho más fácil y más confiable que hacerlo con Awk, como jq:

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

También puede hacer esto con herramientas que probablemente ya estén instaladas en su sistema, como Pythonjson module , y así evitar cualquier dependencia extra, sin dejar de tener el beneficio de un analizador JSON adecuado. Lo siguiente supone que desea utilizar UTF-8, que el JSON original debe ser codificado y es lo que la mayoría de los terminales modernos utilizan también:

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'])"

Notas históricas

Esta respuesta originalmente recomendó jsawk , que aún debería funcionar, pero es un poco más engorroso de usar que jq, y depende de que se instale un intérprete de JavaScript independiente que es menos común que un intérprete de Python, por lo que las respuestas anteriores preferible:

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

Esta respuesta también utilizó originalmente la API de Twitter de la pregunta, pero esa API ya no funciona, por lo que es difícil copiar los ejemplos para probar, y la nueva API de Twitter requiere claves de API, por lo que he cambiado a usar la API de GitHub que se puede usar fácilmente sin claves de API. La primera respuesta a la pregunta original sería:

curl 'http://twitter.com/users/username.json' | jq -r '.text'
 671
Author: Brian Campbell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-09 18:06:18

Para extraer rápidamente los valores de una clave en particular, personalmente me gusta usar "grep-o", que solo devuelve la coincidencia de la expresión regular. Por ejemplo, para obtener el campo "texto" de los tweets, algo como:

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

Esta expresión regular es más robusta de lo que podría pensar; por ejemplo, trata bien con cadenas que tienen comas incrustadas y comillas escapadas dentro de ellas. Creo que con un poco más de trabajo se podría hacer uno que está realmente garantizado para extraer el valor, si es atómico. (Si tiene anidando, entonces una expresión regular no puede hacerlo, por supuesto.)

Y para limpiar aún más (aunque manteniendo el escape original de la cadena) puede usar algo como: | perl -pe 's/"text"://; s/^"//; s/",$//'. (Hice esto para este análisis.)

Para todos los enemigos que insisten en que debe utilizar un analizador JSON real yes sí, eso es esencial para la corrección, pero

  1. Para hacer un análisis realmente rápido, como contar valores para verificar errores de limpieza de datos o obtener una idea general de los datos, golpeando algo en el la línea de comandos es más rápida. Abrir un editor para escribir un script es una distracción.
  2. grep -o es órdenes de magnitud más rápido que la biblioteca estándar de Python json, al menos cuando se hace esto para tweets (que son ~2 KB cada uno). No estoy seguro si esto es solo porque json es lento (debería compararlo con yajl en algún momento); pero en principio, una expresión regular debería ser más rápida ya que es un estado finito y mucho más optimizable, en lugar de un analizador que tiene que soportar la recursión, y en este caso, gasta construir árboles para estructuras que no te importan. (Si alguien escribiera un transductor de estado finito que hiciera un análisis JSON adecuado (con profundidad limitada), ¡sería fantástico! Mientras tanto tenemos "grep-o".)

Para escribir código mantenible, siempre uso una biblioteca de análisis real. No he probado jsawk , pero si funciona bien, eso abordaría el punto #1.

Una última solución, más loca: escribí un script que usa Python json y extrae las claves que desea, en columnas separadas por tabulación; luego canalizo a través de una envoltura alrededor de awk que permite el acceso con nombre a las columnas. Aquí: los scripts json2tsv y tsvawk. Así que para este ejemplo sería:

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

Este enfoque no aborda #2, es más ineficiente que un solo script de Python, y es un poco frágil: obliga a la normalización de nuevas líneas y pestañas en valores de cadena, para jugar bien con la vista del mundo delimitada por campos/registros de awk. Pero te permite permanecer en la línea de comandos, con más exactitud que grep -o.

 226
Author: Brendan OConnor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-27 08:12:47

Sobre la base de que algunas de las recomendaciones aquí (esp en los comentarios) sugirieron el uso de Python, me decepcionó no encontrar un ejemplo.

Por lo tanto, aquí hay un trazador de líneas para obtener un solo valor de algunos datos JSON. Asume que está canalizando los datos (desde algún lugar) y por lo tanto debería ser útil en un contexto de scripting.

echo '{"hostname":"test","domainname":"example.com"}' | python -c 'import json,sys;obj=json.load(sys.stdin);print obj[0]["hostname"]'
 149
Author: paulkmoore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-05 20:44:34

Siguiendo el ejemplo de MartinR y Boecko:

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

Eso le dará una salida extremadamente amigable con grep. Muy conveniente:

$ curl -s 'http://twitter.com/users/username.json' | python -mjson.tool | grep my_key
 117
Author: jnrg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-15 12:50:45

Usted podría simplemente descargar jq binario para su plataforma y ejecutar (chmod +x jq):

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

Extrae el atributo "name" del objeto json.

jq homepage dice que es como sed para los datos JSON.

 111
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-30 15:02:49

Use El soporte JSON de Python en lugar de usar awk!

Algo como esto:

curl -s http://twitter.com/users/username.json | \
    python -c "import json,sys;obj=json.load(sys.stdin);print obj['name'];"
 88
Author: martinr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-01 15:00:14

Usando Nodo.js

Si el sistema tiene instalado node, es posible usar las banderas de script -p print y -e evaulate con JSON.parse para sacar cualquier valor que sea necesario.

Un ejemplo simple usando la cadena JSON { "foo": "bar" } y sacando el valor de "foo":

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

Debido a que tenemos acceso a cat y otras utilidades, podemos usar esto para archivos:

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

O cualquier otro formato como una URL que contenga JSON:

$ node -pe 'JSON.parse(process.argv[1]).name' "$(curl -s https://api.github.com/users/trevorsenior)"
Trevor Senior
 75
Author: x9hb8wcy6quezjk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-26 14:14:09

Has preguntado cómo disparar en el pie y estoy aquí para proporcionar la munición:

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

Podrías usar tr -d '{}' en lugar de sed. Pero dejarlos fuera por completo parece tener el efecto deseado también.

Si desea eliminar las comillas externas, canalice el resultado de lo anterior a través de sed 's/\(^"\|"$\)//g'

Creo que otros han sonado suficiente alarma. Estaré esperando con un teléfono celular para llamar a una ambulancia. Dispare cuando esté listo.

 44
Author: Dennis Williamson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-24 00:08:01

Usando Bash con Python

Cree una función bash en su .bash_rc file

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

Entonces

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

Aquí está la misma función, pero con comprobación de errores.

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

Donde $# -ne 1 se asegura de al menos 1 entrada, y-t 0 se asegura de que está redirigiendo desde una tubería.

Lo bueno de esta implementación es que puede acceder a los valores json anidados y obtener json a cambio. =)

Ejemplo:

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

Si quieres ser realmente elegante, podrías pretty imprimir los datos:

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"
}
 36
Author: Joe Heyming,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-03 16:35:08

Analizando JSON con PHP CLI

Podría decirse que fuera de tema, pero ya que reina la precedencia, esta pregunta permanece incompleta sin una mención de nuestro fiel y fiel PHP, ¿tengo razón?

Usando el mismo JSON de ejemplo pero vamos a asignarlo a una variable para reducir la oscuridad.

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

Ahora para PHP goodness, usando file_get_contents y el php://stdin contenedor de flujo.

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

O como se indica usando fgets y el flujo ya abierto en Constante CLI STDIN.

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

NJoy!

 19
Author: nickl-,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-22 12:51:24

TickTick es un analizador JSON escrito en bash (

Aquí está el fragmento del autor de su artículo, Imagine un mundo donde Bash soporte 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
 18
Author: CoolAJ86,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-12 01:41:34

Versión nativa de Bash: También funciona bien con barras invertidas ( \ ) y comillas (")

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]
 17
Author: maikel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-12 20:43:56

Versión que usa Ruby y http://flori.github.com/json /

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

O más concisamente:

$ < file.json ruby -r rubygems -r json -e "puts JSON.pretty_generate(JSON[STDIN.read]);"
 11
Author: boecko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-27 01:44:18

Puede utilizar jshon:

curl 'http://twitter.com/users/username.json' | jshon -e text
 5
Author: kev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-11 14:48:10

Desafortunadamente, la respuesta votada que usa grep devuelve la coincidencia completa que no funcionó en mi escenario, pero si sabe que el formato JSON se mantendrá constante, puede usar lookbehind y lookahead para extraer solo los valores deseados.

# 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
 5
Author: Daniel Sokolowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-16 18:20:54

Aquí hay una forma de hacerlo con 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
Author: ghostdog74,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-24 00:08:48

Alguien que también tiene archivos xml, podría querer mirar mi Xidel. Es un procesador cli, libre de dependencias JSONiq. (es decir, también admite XQuery para el procesamiento xml o json)

El ejemplo en la pregunta sería:

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

O con mi propia sintaxis de extensión no estándar:

 xidel -e 'json("http://twitter.com/users/username.json").name'
 4
Author: BeniBela,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-30 17:09:01

Para un análisis JSON más complejo, sugiero usar el módulo jsonpath de python (por Stefan Goessner) -

  1. Instalarlo -

Sudo easy_install-U jsonpath

  1. Úsalo -

Archivo de ejemplo.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
    }
  }
}

Analizarlo (extraer todos los títulos de libros con precio

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

Saldrá -

Sayings of the Century
Moby Dick

NOTA: La línea de comandos anterior no incluye la comprobación de errores. para la solución completa con la comprobación de errores, debe crear un pequeño script de python y envolver el código con try-except.

 4
Author: shlomosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-01 09:05:56

Si tienes php :

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

Por ejemplo:
tenemos un recurso que proporciona json con los códigos iso de los países: http://country.io/iso3.json y podemos verlo fácilmente en una concha con rizo:

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

Pero no parece muy conveniente, y no es legible, mejor analizar json y ver estructura legible:

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

Este código imprimirá algo como:

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

Si tiene matrices anidadas, esta salida se verá mucho mejor...

Espero que esto útil...

 4
Author: Vladimir Kovpak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-19 11:03:25

Puedes probar algo como esto -

curl -s 'http://twitter.com/users/jaypalsingh.json' | 
awk -F=":" -v RS="," '$1~/"text"/ {print}'
 3
Author: jaypal singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-06 23:39:03

Analizar JSON es doloroso en un script de shell. Con un lenguaje más apropiado, cree una herramienta que extraiga atributos JSON de una manera consistente con las convenciones de scripts de shell. Puede usar su nueva herramienta para resolver el problema inmediato de scripts de shell y luego agregarlo a su kit para situaciones futuras.

Por ejemplo, considere una herramienta jsonlookup tal que si digo que jsonlookup access token id devolverá el atributo id definida en el atributo token definida dentro de la attribute access from stdin, which is presumably JSON data. Si el atributo no existe, la herramienta no devuelve nada (estado de salida 1). Si el análisis falla, salga del estado 2 y envíe un mensaje a stderr. Si la búsqueda tiene éxito, la herramienta imprime el valor del atributo.

Habiendo creado una herramienta unix con el propósito preciso de extraer valores JSON, puede usarla fácilmente en scripts de shell:

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

Cualquier lenguaje servirá para la implementación de jsonlookup. Aquí está un versión bastante concisa de 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
Author: mcnabicus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-02 21:28:01

Un dos líneas que usa python. Funciona particularmente bien si estás escribiendo un solo archivo. sh y no quieres depender de otro archivo .py. También aprovecha el uso de pipe |. echo "{\"field\": \"value\"}" puede ser reemplazado por cualquier cosa que imprima un json a la salida estándar.

echo "{\"field\": \"value\"}" | python -c 'import sys, json
print(json.load(sys.stdin)["field"])'
 3
Author: Adam Kurkiewicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-04 17:47:39

Este es un buen caso de uso para pythonpy:

curl 'http://twitter.com/users/username.json' | py 'json.load(sys.stdin)["name"]'
 3
Author: RussellStewart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-27 20:25:55

Si pip está disponible en el sistema entonces:

$ pip install json-query

Ejemplos de uso:

$ 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
Author: Alexey Dubkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-27 04:37:44

Ahora que Powershell es multiplataforma, pensé en abrirlo camino, ya que me parece bastante intuitivo y extremadamente simple.

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

ConvertFrom-Json convierte el JSON en un objeto personalizado de Powershell, para que pueda trabajar fácilmente con las propiedades a partir de ese momento. Si solo quisieras la propiedad 'id' por ejemplo, simplemente harías esto:

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

Si quisieras invocar todo desde Bash, entonces tendrías que llamarlo como esto:

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

Por supuesto, hay una forma pura de Powershell de hacerlo sin curl, que sería:

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

Finalmente, también está 'ConvertTo-Json' que convierte un objeto personalizado a JSON con la misma facilidad. He aquí un ejemplo:

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

Que produciría un buen JSON como este:

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

}

Es cierto que usar un shell de Windows en Unix es algo sacrílego, pero Powershell es realmente bueno en algunas cosas, y analizar JSON y XML son un par de ellos. Este es el Página de GitHub para la versión multiplataforma https://github.com/PowerShell/PowerShell

 3
Author: user2233949,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-20 12:37:44

Este es otro bash & python respuesta híbrida. Publiqué esta respuesta porque quería procesar una salida JSON más compleja, pero, reduciendo la complejidad de mi aplicación bash. Quiero abrir el siguiente objeto JSON desde http://www.arcgis.com/sharing/rest/info?f=json en bash:

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

Mientras que este enfoque aumenta la complejidad en la función Python, el uso de bash se vuelve más 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 salida del script anterior is:

He añadido soporte para matrices, por lo que puede utilizar .length y, si la fuente es un array de cadenas, puedes usar .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

Que produce:

  • 1
  • [{"escala": 591657527.591555, "resolución": 156543.03392800014, "nivel": 0}, {"escala": 295828763.795777, "resolución": 78271.51696399994, "nivel": 1}, {"escala": 147914381.897889, "resolución": 39135.75848200009, "nivel": 2}, {"escala": 73957190.948944, "resolución": 19567.87924099992, "nivel": 3}, {"escala": 36978595.474472, "resolución": 9783.93962049996, "nivel": 4}, {"escala": 18489297.737236, "resolución": 4891.96981024998, "nivel": 5}, {"escala": 9244648.868618, "resolución": 2445.98490512499, "nivel": 6}, {"escala": 4622324.434309, "resolución": 1222.992452562495, "level": 7}, {"scale": 2311162.217155, "resolution": 611.4962262813797, "level": 8}, {"scale": 1155581.108577, "resolution": 305.74811314055756, "level": 9}, {"escala": 577790.554289, "resolución": 152.87405657041106, "nivel": 10}, {"escala": 288895.277144, "resolución": 76.43702828507324, "nivel": 11}, {"escala": 144447.638572, "resolución": 38.21851414253662, "nivel": 12}, {"escala": 72223.819286, "resolución": 19.10925707126831, "nivel": 13}, {"escala": 36111.909643, "resolución": 9.554628535634155, "level": 14}, {"scale": 18055.954822, "resolution": 4.77731426794937, "level": 15}, {"scale": 9027.977411, "resolution": 2.388657133974685, "level": 16}, {"scale": 4513.988705, "resolución": 1.1943285668550503, "nivel": 17}, {"escala": 2256.994353, "resolución": 0.5971642835598172, "nivel": 18}, {"escala": 1128.497176, "resolución": 0.29858214164761665, "nivel": 19}, {"escala": 564.248588, "resolución": 0.14929107082380833, "nivel": 20}, {"escala": 282.124294, "resolución": 0.07464553541190416, "level": 21}, {"scale": 141.062147, "resolution": 0.03732276770595208, "level": 22}, {"scale": 70.5310735, "resolution": 0.01866138385297604, "level": 23}]
  • 24
  • {"escala": 70.5310735, "resolución": 0.01866138385297604, "nivel": 23}
 3
Author: Stephen Quan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-19 21:23:25

Si alguien solo quiere extraer valores de objetos JSON simples sin la necesidad de estructuras anidadas, es posible usar expresiones regulares sin siquiera salir del bash.

Aquí hay una función que definí usando expresiones regulares bash basadas en el estándar 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
}

Advertencias: los objetos y arrays no son soportados como valor, pero todos los otros tipos de valor definidos en el estándar son soportados. Además, un par se emparejará sin importar cuán profundo sea el JSON documento es tan largo como tiene exactamente el mismo nombre de clave.

Usando el ejemplo de 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
 3
Author: Helder Pereira,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-20 14:33:32

Aquí hay una buena referencia . En este caso:

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
Author: Max Barrass,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-25 04:04:43

Niet es una herramienta que te ayuda a extraer datos de archivos json o yaml directamente en tu CLI shell/bash.

$ pip install niet

Considere un archivo json llamado project.json con el siguiente contenido:

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

Puedes usar niet así:

$ PROJECT_NAME=$(niet project.json project.meta.name)
$ echo ${PROJECT_NAME}
project-sample
 2
Author: Herve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-12 15:52:14

Usé esto para extraer la duración del video de la salida json de ffprobe :

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`

Se puede usar para extraer valor de cualquier json :

value=`echo "$jsondata"|grep -w \"key_name\" |tail -1 | cut -d\" -f4
 2
Author: Ehsan Chavoshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-19 13:20:02