examples - Analizando JSON con herramientas Unix
jq json examples bash (30)
Análisis de JSON con PHP CLI
Posiblemente fuera de tema, pero como prevalece la prioridad, esta pregunta permanece incompleta sin una mención de nuestro PHP confiable y fiel, ¿verdad?
Usando el mismo ejemplo JSON, pero asignémoslo a una variable para reducir la oscuridad.
$ export JSON=''{"hostname":"test","domainname":"example.com"}''
Ahora, para la bondad de PHP, use file_get_contents y el contenedor php://stdin stream.
$ echo $JSON|php -r ''echo json_decode(file_get_contents("php://stdin"))->hostname;''
o como se indicó utilizando fgets y el flujo ya abierto en la constante CLI STDIN .
$ echo $JSON|php -r ''echo json_decode(fgets(STDIN))->hostname;''
nJoy!
Estoy tratando de analizar JSON devuelto de una solicitud de rizo, 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 -vk=text
un campo específico (indicado por el -vk=text
)?
Usando Bash con Python
Crea una función bash en tu archivo .bash_rc
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 la 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 puedes 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, puedes 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"
}
Usando Node.js
Si el sistema tiene un node instalado, es posible usar las marcas de script -p
print y -e
evaulate con JSON.parse
para extraer cualquier valor que sea necesario.
Un ejemplo simple usando la cadena JSON { "foo": "bar" }
y extrayendo el valor de "foo":
$ node -pe ''JSON.parse(process.argv[1]).foo'' ''{ "foo": "bar" }''
bar
Como 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
Ahora que Powershell es multiplataforma, pensé que me abriría 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, por lo que puede trabajar fácilmente con las propiedades desde ese punto en adelante. Si solo quisieras la propiedad ''id'' por ejemplo, solo harías esto:
curl -s ''https://api.github.com/users/lambda'' | ConvertFrom-Json | select -ExpandProperty id
Si quisieras invocar todo desde Bash, entonces deberías llamarlo así:
powershell ''curl -s "https://api.github.com/users/lambda" | ConvertFrom-Json''
Por supuesto, hay una forma pura de Powershell para hacerlo sin rizo, 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. Aquí hay un ejemplo:
(New-Object PsObject -Property @{ Name = "Tester"; SomeList = @(''one'',''two'',''three'')}) | ConvertTo-Json
Lo que produciría un bonito JSON como este:
{
"Name": "Tester",
"SomeList": [
"one",
"two",
"three"
]
}
Es cierto que usar un shell de Windows en Unix es un tanto sacrilegio, pero Powershell es realmente bueno en algunas cosas, y el análisis de JSON y XML son un par de ellas. Esta es la página de GitHub para la versión multiplataforma https://github.com/PowerShell/PowerShell
Alguien que también tiene archivos XML, puede querer mirar mi Xidel . Es un procesador JSONiq libre de JSONiq . (es decir, también es compatible con XQuery para 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''
Analizar JSON es doloroso en un script de shell. Con un lenguaje más apropiado, cree una herramienta que extraiga los atributos JSON de una manera consistente con las convenciones de shell scripting. Puede usar su nueva herramienta para resolver el problema inmediato de shell scripting y luego agregarla a su kit para situaciones futuras.
Por ejemplo, considere una herramienta jsonlookup tal que si digo jsonlookup access token id
devolverá el atributo id definido dentro del atributo token definido dentro del atributo acceso desde stdin, que es presumiblemente datos de JSON. Si el atributo no existe, la herramienta no devuelve nada (estado de salida 1). Si el análisis falla, salga del estado 2 y un mensaje a stderr. Si la búsqueda se realiza correctamente, 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í hay una versión de Python bastante concisa:
#!/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
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
}
}
}''
Desafortunadamente, la respuesta más 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 look behind 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
Esta es otra respuesta híbrida de bash
y python
. 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
}
}
Si bien este enfoque aumenta la complejidad de la función de 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 es:
- {"owningSystemUrl": " http://www.arcgis.com ", "authInfo": {"tokenServicesUrl": " https://www.arcgis.com/sharing/rest/generateToken ", "isTokenBasedSecurity": true} }
- {"tokenServicesUrl": " https://www.arcgis.com/sharing/rest/generateToken ", "isTokenBasedSecurity": true}
- https://www.arcgis.com/sharing/rest/generateToken
Agregué soporte para arrays, por lo que puede usar .length
y, si la fuente es un array de cadenas, puede 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
Qué salidas:
- 1
- [{"escala": 591657527.591555, "resolución": 156543.03392800014, "nivel": 0}, {"escala": 295828763.795777, "resolución": 78271.51696399994, "nivel": 1}, {"escala": 147914381.89788989 "" resolución ": 39135.75848200009," nivel ": 2}, {" escala ": 73957190.948944," resolución ": 19567.87924099992," nivel ": 3}, {" escala ": 36978595.474472," resolución ": 9783.93962049996," nivel ": 4 , {"scale": 18489297.737236, "resolution": 4891.96981024998, "level": 5}, {"scale": 9244648.868618, "resolution": 2445.98490512499, "level": 6}, {"scale": 4622324.434309, "resolution ": 1222.992452562495," nivel ": 7}, {" escala ": 2311162.217155,"resolución": 611.4962262813797, "nivel": 8}, {"escala": 1155581.108577, "resolución": 305.74811314055756, "nivel": 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.2185141425253662, "nivel": 12}, {"escala": 72223.819286, "resolución": 19.10925707126831, "nivel": 13}, {"escala": 36111.909643, "resolución": 9.554628535634155, "nivel": 14}, {"escala": 18055.954822, "resolución": 4.77731426794937, "nivel": 15}, {"escala": 9027.977411, "resolución": 2.388657133974685,"nivel": 16}, {"escala": 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," resolution ": 0.0746455355144164164 "nivel": 21}, {"escala": 141.062147, "resolución": 0.03732276770595208, "nivel": 22}, {"escala": 70.5310735, "resolución": 0.01866138385297604, "nivel": 23}]scale ": 2256.994353," resolution ": 0.5971642835598172," level ": 18}, {" scale ": 1128.497176," resolution ": 0.29858214164761665," level ": 19}, {" scale ": 564.248588," resolution ": 0.149291070823808 , "nivel": 20}, {"escala": 282.124294, "resolución": 0.07464553541190416, "nivel": 21}, {"escala": 141.062147, "resolución": 0.03732276770595208, "nivel": 22}, {" escala ": 70.5310735," resolución ": 0.01866138385297604," nivel ": 23}]scale ": 2256.994353," resolution ": 0.5971642835598172," level ": 18}, {" scale ": 1128.497176," resolution ": 0.29858214164761665," level ": 19}, {" scale ": 564.248588," resolution ": 0.149291070823808 , "nivel": 20}, {"escala": 282.124294, "resolución": 0.07464553541190416, "nivel": 21}, {"escala": 141.062147, "resolución": 0.03732276770595208, "nivel": 22}, {" escala ": 70.5310735," resolución ": 0.01866138385297604," nivel ": 23}]14929107082380833, "nivel": 20}, {"escala": 282.124294, "resolución": 0.07464553541190416, "nivel": 21}, {"escala": 141.062147, "resolución": 0.03732276770595208, "nivel": 22}, { "escala": 70.5310735, "resolución": 0.01866138385297604, "nivel": 23}]14929107082380833, "nivel": 20}, {"escala": 282.124294, "resolución": 0.07464553541190416, "nivel": 21}, {"escala": 141.062147, "resolución": 0.03732276770595208, "nivel": 22}, { "escala": 70.5310735, "resolución": 0.01866138385297604, "nivel": 23}]
- 24
- {"escala": 70.5310735, "resolución": 0.01866138385297604, "nivel": 23}
Existen varias herramientas diseñadas específicamente para manipular JSON desde la línea de comandos, y serán mucho más fáciles y más confiables 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 Python que usa el módulo json
, y así evitar cualquier dependencia adicional, mientras sigue teniendo la ventaja de un analizador JSON adecuado. Lo siguiente asume que desea usar UTF-8, en el que se debe codificar el JSON original y es lo que la mayoría de los terminales modernos usan 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 historicas
Esta respuesta recomendó originalmente jsawk , que aún debería funcionar, pero es un poco más incómodo de usar que jq
, y depende de la instalación de un intérprete de JavaScript independiente, que es menos común que un intérprete de Python, por lo que las respuestas anteriores probablemente sean preferibles:
curl -s ''https://api.github.com/users/lambda'' | jsawk -a ''return this.name''
Esta respuesta también usó originalmente la API de Twitter de la pregunta, pero esa API ya no funciona, lo que dificulta copiar los ejemplos para probarlos, y la nueva API de Twitter requiere claves de API, por lo que he cambiado a usar la API de GitHub Se puede utilizar fácilmente sin claves API. La primera respuesta para la pregunta original sería:
curl ''http://twitter.com/users/username.json'' | jq -r ''.text''
Me has preguntado cómo dispararte en el pie y estoy aquí para proporcionarte la munición:
curl -s ''http://twitter.com/users/username.json'' | sed -e ''s/[{}]/''''/g'' | awk -v RS='',"'' -F: ''/^text/ {print $2}''
Puedes usar tr -d ''{}''
lugar de sed
. Pero dejarlos completamente parece tener también el efecto deseado.
Si desea quitar 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. Fuego cuando esté listo.
Para extraer rápidamente los valores de una clave en particular, personalmente me gusta usar "grep -o", que solo devuelve la coincidencia de expresiones regulares. 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 piensas; por ejemplo, trata bien las cadenas que tienen comas incrustadas y comillas escapadas dentro de ellas. Creo que con un poco más de trabajo podrías hacer uno que realmente garantice extraer el valor, si es atómico. (Si tiene anidación, entonces una expresión regular no puede hacerlo, por supuesto).
Y para mayor limpieza (aunque manteniendo el escape original de la cuerda) puedes usar algo como: | perl -pe ''s/"text"://; s/^"//; s/",$//''
| perl -pe ''s/"text"://; s/^"//; s/",$//''
| perl -pe ''s/"text"://; s/^"//; s/",$//''
. (Hice esto para este análisis .)
A todos los enemigos que insisten en que debe usar un analizador JSON real, sí, eso es esencial para la corrección, pero
- Para hacer un análisis realmente rápido, como contar valores para verificar errores de limpieza de datos o tener una idea general de los datos, golpear algo en la línea de comando es más rápido. Abrir un editor para escribir un guión es una distracción.
-
grep -o
es órdenes de magnitud más rápido que la bibliotecajson
estándar de Python, al menos al hacer esto para los tweets (que son ~ 2 KB cada uno). No estoy seguro de si esto es solo porquejson
es lento (debería compararme 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 gran cantidad de árboles de CPU para las estructuras que no le interesan. (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 el "grep -o").
Para escribir código mantenible, siempre uso una biblioteca de análisis real. No he intentado jsawk , pero si funciona bien, se trataría el punto # 1.
Una última solución, más extraña: escribí un script que usa Python json
y extrae las claves que desea, en columnas separadas por tabulaciones; luego canalizo una envoltura alrededor de awk
que permite el acceso con nombre a las columnas. Aquí: los scripts json2tsv y tsvawk . Entonces para este ejemplo sería:
json2tsv id text < tweets.json | tsvawk ''{print "tweet " $id " is: " $text}''
Este enfoque no aborda el # 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 tabulaciones en los valores de cadena, para jugar bien con la visión del mundo de campo / registro delimitado por awk. Pero sí te permite permanecer en la línea de comandos, con más corrección que grep -o
.
Para un análisis JSON más complejo, sugiero usar el módulo jsonpath de Python (por Stefan Goessner) -
- Instalarlo -
sudo easy_install -U jsonpath
- Usalo
Ejemplo 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
}
}
}
Analícelo (extraiga todos los títulos de libros con precio <10) -
$ 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 comando anterior no incluye la comprobación de errores. para una solución completa con comprobación de errores, debe crear un pequeño script de Python y envolver el código con try-except.
Puede descargar jq
binary 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
página de inicio de jq
dice que es como sed
para los datos de JSON.
Puedes probar algo como esto -
curl -s ''http://twitter.com/users/jaypalsingh.json'' |
awk -F=":" -v RS="," ''$1~/"text"/ {print}''
Puedes usar jshon
:
curl ''http://twitter.com/users/username.json'' | jshon -e text
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
Si tienes php :
php -r ''var_export(json_decode(`curl http://twitter.com/users/username.json`, 1));''
Por ejemplo:
tenemos un recurso que proporciona códigos iso a json with countries: http://country.io/iso3.json y podemos verlo fácilmente en un shell con curl:
curl http://country.io/iso3.json
pero no parece muy conveniente, y no legible, mejor analizar json y ver la 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 sea de ayuda ...
Siguiendo el ejemplo de MartinR y Boecko:
$ curl -s ''http://twitter.com/users/username.json'' | python -mjson.tool
Eso te dará una salida extremadamente amigable con grep. Muy conveniente:
$ curl -s ''http://twitter.com/users/username.json'' | python -mjson.tool | grep my_key
Sobre la base de que algunas de las recomendaciones aquí (especialmente en los comentarios) sugirieron el uso de Python, me decepcionó no encontrar un ejemplo.
Por lo tanto, aquí hay una sola línea para obtener un valor único de algunos datos JSON. Se supone que está canalizando los datos en (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"]''
Un two-liner que utiliza python. Funciona particularmente bien si está escribiendo un solo archivo .sh y no desea depender de otro archivo .py. También aprovecha el uso de la tubería |
. echo "{/"field/": /"value/"}"
se puede reemplazar 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"])''
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''];"
Versión de Bash nativo: 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]
Versión que utiliza 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]);"
Aquí hay una buena referencia . En este caso:
{
project: {
meta: {
name: project-sample
}
}
Niet es una herramienta que le ayuda a extraer datos de archivos json o yaml directamente en su CLI shell / bash.
$ PROJECT_NAME=$(niet project.json project.meta.name)
$ echo ${PROJECT_NAME}
project-sample
Considere un archivo json llamado project.json con el siguiente contenido:
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`
Puedes usar niet así:
value=`echo "$jsondata"|grep -w /"key_name/" |tail -1 | cut -d/" -f4
TickTick es un analizador JSON escrito en bash (<250 líneas de código)
Aquí está el fragmento del autor de su artículo, Imagina un mundo donde Bash apoya a 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
Si alguien solo quiere extraer valores de objetos JSON simples sin la necesidad de estructuras anidadas, es posible usar expresiones regulares sin siquiera abandonar el 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 las matrices no se admiten como valor, pero todos los demás tipos de valores definidos en el estándar son compatibles. Además, se emparejará un par sin importar qué tan profundo esté en el documento JSON, siempre que tenga 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
No puedo usar ninguna de las respuestas aquí. No hay jq disponible, no hay arreglos de shell, no declara, no grep -P, no mira atrás y mira adelante, no Python, no Perl, no Ruby, no ... ni Bash ... Las respuestas restantes simplemente no funcionan bien. JavaScript me sonaba familiar, pero la lata dice Nescaffe, por lo que es un no go, también :) Incluso si está disponible, para mi simple necesidad, serían excesivos y lentos.
Sin embargo, es extremadamente importante para mí obtener muchas variables de la respuesta con formato json de mi módem. Lo estoy haciendo en un sh con BusyBox muy recortado en mis enrutadores! No hay problemas al usar awk solo: simplemente configure delimitadores y lea los datos. Para una sola variable, eso es todo!
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]} } }''
¿Recuerdas que no tengo matrices? Tuve que asignar dentro de los datos analizados awk a las 11 variables que necesito en un script de shell. Dondequiera que mirara, se decía que era una misión imposible. No hay problema con eso, también.
Mi solución es simple. Este código: 1) analizará el archivo .json de la pregunta (en realidad, tomé prestada una muestra de datos de trabajo de la respuesta más votada) y seleccioné los datos citados, más 2) crearé variables de shell desde el awk asignando un shell con nombre libre nombres de variables
$ pip install niet
No hay problemas con espacios en blanco dentro. En mi uso, el mismo comando analiza una salida de una sola línea larga. A medida que se usa eval, esta solución es adecuada solo para datos confiables. Es sencillo adaptarlo para recoger datos no citados. Para un gran número de variables, la ganancia de velocidad marginal puede lograrse usando else if. La falta de matriz obviamente significa: no hay registros múltiples sin necesidad de tocar más. Pero donde hay matrices disponibles, adaptar esta solución es una tarea simple.
La respuesta de @maikel sed casi funciona (pero no puedo comentarla). Para mis datos bien formateados, funciona. No tanto con el ejemplo que se usa aquí (las comillas que faltan lo eliminan). Es complicado y difícil de modificar. Además, no me gusta tener que hacer 11 llamadas para extraer 11 variables. ¿Por qué?Programé 100 bucles extrayendo 9 variables: ¡la función sed tomó 48.99 segundos y mi solución tomó 0.91 segundos! ¿No es justo? Haciendo solo una extracción de 9 variables: 0.51 vs. 0.02 seg.