Filtrado y selección de JSON con pipelines de jq
Navegue por objetos y arrays anidados mediante selectores, tuberías y el filtro select de jq.
Filtrado y selección de JSON con pipelines de jq es una lección gratuita de Linux Command Line & Bash Scripting Mastery en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Linux Command Line & Bash Scripting Mastery, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Linux Command Line & Bash Scripting Mastery incluye 4 lecciones en total.
¿Qué es jq y por qué utilizarlo?
jq es una herramienta ligera y potente de línea de comandos para analizar, filtrar y transformar datos JSON. Es el sed de JSON: se introduce JSON mediante una tubería y se obtiene de vuelta una salida estructurada.
- Está preinstalado en la mayoría de las distribuciones de Linux o se puede instalar mediante
apt install jq/brew install jq - Funciona perfectamente en canalizaciones del shell con
curl,caty otras herramientas - Admite filtrado, mapeo, reducción y conversión de formatos
La invocación básica es: jq '<filter>' file.json o mediante una tubería, como cat file.json | jq '<filter>'. El filtro . (punto) es la identidad: muestra todo el documento con formato legible.
# Pretty-print a JSON file
jq '.' data.json
# Or pipe from curl
curl -s https://api.github.com/users/torvalds | jq '.'Selección de campos de objetos con notación de punto
Para acceder a un campo de un objeto JSON, use la notación de punto: .fieldName. Puede encadenar selectores para recorrer objetos anidados.
.name— campo de nivel superior.address.city— campo anidado."field-with-dash"— los campos con caracteres especiales necesitan comillas
Si el campo no existe, jq devuelve null en lugar de producir un error. Esto permite utilizarlo de forma segura en scripts sin comprobaciones adicionales de valores nulos para campos opcionales.
# Given: {"name":"Alice","address":{"city":"Berlin","zip":"10115"}}
echo '{"name":"Alice","address":{"city":"Berlin","zip":"10115"}}' | jq '.name'
# Output: "Alice"
echo '{"name":"Alice","address":{"city":"Berlin","zip":"10115"}}' | jq '.address.city'
# Output: "Berlin"Acceso a elementos de arrays e iteración
Se accede a los arrays JSON mediante la notación de corchetes. jq utiliza índices basados en cero.
.items[0]— primer elemento.items[-1]— último elemento.items[1:3]— segmento (desde el índice 1 hasta antes del 3).items[]— descompone el array: muestra cada elemento como un valor independiente (este es el iterador)
El iterador [] es fundamental en las canalizaciones de jq: permite aplicar los filtros posteriores a cada elemento de forma independiente.
# Given an array of users
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Carol"}]' | jq '.[0]'
# Output: {"name":"Alice"}
# Iterate all elements and extract .name from each
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Carol"}]' | jq '.[].name'
# Output:
# "Alice"
# "Bob"
# "Carol"Construcción de canalizaciones de jq con el operador de tubería
Al igual que la tubería del shell |, jq tiene su propio operador de tubería interno. Este pasa la salida de un filtro como entrada del siguiente.
jq '.users[] | .name'— itera sobre los usuarios y después extrae el nombre de cada unojq '.data | .items[] | .id'— navega hasta data, descompone items y extrae id
Las tuberías dentro de una expresión jq permiten construir transformaciones complejas paso a paso. Cada etapa recibe todo lo que produjo la etapa anterior, incluidos los múltiples valores generados por un iterador.
Idea clave: cuando un iterador produce N valores, cada filtro posterior se ejecuta N veces, una vez por valor.
# Nested pipeline: navigate -> iterate -> extract
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
| jq '.users[] | .name'
# Output:
# "Alice"
# "Bob"
# Chain more stages
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
| jq '.users[] | .age'
# Output:
# 30
# 25Filtrado con select()
El filtro select(condition) deja pasar un valor únicamente si la condición es verdadera; de lo contrario, no produce ninguna salida. Es el equivalente en jq de grep o WHERE en SQL.
select(.age > 18)— conserva los objetos cuya edad es mayor que 18select(.status == "active")— comprobación de igualdadselect(.name | startswith("A"))— prueba de cadena anidada
Combine select con el iterador para filtrar arrays: .items[] | select(.active) muestra únicamente los elementos cuyo .active sea verdadero.
# Filter array elements by a condition
echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":25}]' \
| jq '.[] | select(.age >= 18) | .name'
# Output:
# "Alice"
# "Carol"
# Filter by string equality
echo '[{"name":"Alice","role":"admin"},{"name":"Bob","role":"user"}]' \
| jq '.[] | select(.role == "admin") | .name'
# Output: "Alice"Reconstrucción de objetos y arrays con {} y []
jq permite remodelar los datos mediante la construcción de objetos nuevos con {} y arrays nuevos con [].
{name: .name, city: .address.city}— selecciona y renombra campos en un objeto nuevo[.items[] | .id]— vuelve a recopilar los valores iterados en un array- Forma abreviada:
{name, age}equivale a{name: .name, age: .age}
Rodear una canalización con [...] se denomina construcción de arrays y es esencial cuando desea obtener un array JSON como salida en lugar de un flujo de valores.
# Reshape: keep only selected fields
echo '[{"id":1,"name":"Alice","password":"secret"},{"id":2,"name":"Bob","password":"secret"}]' \
| jq '[.[] | {id, name}]'
# Output:
# [
# {"id": 1, "name": "Alice"},
# {"id": 2, "name": "Bob"}
# ]
# Collect filtered names into an array
echo '[{"name":"Alice","active":true},{"name":"Bob","active":false}]' \
| jq '[.[] | select(.active) | .name]'
# Output: ["Alice"]Trabajo con arrays anidados y descenso recursivo
El JSON del mundo real suele estar profundamente anidado. jq proporciona dos herramientas para la navegación profunda:
.a.b.c— ruta explícita cuando se conoce la estructura.. | .fieldName?— descenso recursivo: recorre todos los nodos del árbol y muestra los valores donde existe la clave
El operador ? (try) suprime los errores cuando un campo no existe en un nodo determinado, algo fundamental al utilizar el descenso recursivo en árboles heterogéneos.
Utilice el descenso recursivo con moderación en documentos grandes: visita todos los nodos y puede ser lento. Prefiera rutas explícitas cuando la estructura sea predecible.
# Explicit deep path
echo '{"a":{"b":{"c":42}}}' | jq '.a.b.c'
# Output: 42
# Recursive descent: find all "id" values anywhere in the tree
echo '{"users":[{"id":1,"profile":{"id":99}},{"id":2}]}' \
| jq '.. | .id?'
# Output:
# 1
# 99
# 2Ejemplo práctico: análisis de respuestas de API con curl
Uno de los casos de uso más habituales de jq es analizar respuestas de API REST obtenidas con curl. Combinar curl -s (silencioso) con una canalización de jq permite extraer datos de forma limpia y apta para scripts.
- Extraer un valor único:
curl -s URL | jq '.field' - Construir una tabla de resumen: iterar sobre un array y reconstruir objetos únicamente con los campos necesarios
- Usar
-r(salida sin formato) para eliminar las comillas que rodean los valores de texto, algo esencial al asignarlos a variables del shell
Consejo: añada siempre -r cuando la salida de jq se vaya a utilizar como variable del shell o se vaya a enviar a otro comando.
#!/usr/bin/env bash
# Fetch GitHub repo info and extract specific fields
REPO="torvalds/linux"
RESPONSE=$(curl -s "https://api.github.com/repos/${REPO}")
# Extract fields
STARS=$(echo "$RESPONSE" | jq -r '.stargazers_count')
LANG=$(echo "$RESPONSE" | jq -r '.language')
DESC=$(echo "$RESPONSE" | jq -r '.description')
echo "Stars : $STARS"
echo "Lang : $LANG"
echo "Desc : $DESC"Uso de map() y map_values()
jq proporciona dos funciones de orden superior prácticas para transformar colecciones:
map(f)— aplica el filtrofa cada elemento de un array y devuelve un array nuevo. Equivale a[.[] | f].map_values(f)— aplicafa cada valor de un objeto o array, conservando las claves o los índices.
Estas funciones son más legibles que envolver manualmente las canalizaciones en [] y constituyen el estilo idiomático de jq para las transformaciones que deben conservarse como arrays.
# map: extract a field from each element
echo '[{"name":"Alice","score":95},{"name":"Bob","score":80}]' \
| jq 'map(.name)'
# Output: ["Alice", "Bob"]
# map with select: filter + transform in one step
echo '[{"name":"Alice","score":95},{"name":"Bob","score":60}]' \
| jq 'map(select(.score >= 70) | .name)'
# Output: ["Alice"]
# map_values: multiply every value in an object by 2
echo '{"a":1,"b":2,"c":3}' | jq 'map_values(. * 2)'
# Output: {"a":2,"b":4,"c":6}Gestión de campos opcionales y valores predeterminados con //
Los datos JSON de fuentes externas suelen ser inconsistentes: puede que falten campos o que tengan el valor null. jq proporciona el operador alternativo // (doble barra) para proporcionar un valor predeterminado.
.nickname // "anonymous"— usa.nicknamesi no es null ni false; de lo contrario, usa"anonymous".count // 0— valor predeterminado numérico- Combínelo con
select:select((.status // "inactive") == "active")
Esto es mucho más conciso que el equivalente del shell, ${VAR:-default}, y se combina fácilmente dentro de canalizaciones más largas.
# Provide defaults for missing/null fields
echo '[{"name":"Alice","role":"admin"},{"name":"Bob"}]' \
| jq '[.[] | {name, role: (.role // "user")}]'
# Output:
# [
# {"name": "Alice", "role": "admin"},
# {"name": "Bob", "role": "user"}
# ]
# Numeric default
echo '{"items":[1,2,3]}' | jq '.total // 0'
# Output: 0Script práctico: analizador de registros JSON
El registro estructurado en JSON es habitual en los sistemas modernos. A continuación se muestra un script realista que lee un archivo de registro JSON delimitado por saltos de línea, filtra las entradas de error y da formato a un resumen legible.
Patrones principales utilizados:
-c(salida compacta): un objeto JSON por línea, útil para enviarlo a bucles del shell mediante una tubería--arg name value— inyecta una variable del shell como argumento de texto de jqselectpara filtrar por nivel del registro-rpara obtener una salida de texto sin formato adecuada paraecho
#!/usr/bin/env bash
# Parse newline-delimited JSON logs and report ERRORs
# Each log line: {"level":"ERROR","msg":"...","ts":"2024-01-15T10:23:00Z","svc":"auth"}
LOG_FILE="/var/log/app/app.log"
LEVEL="ERROR"
echo "=== $LEVEL entries in $LOG_FILE ==="
jq -r --arg lvl "$LEVEL" \
'select(.level == $lvl) | "[\(.ts)] [\(.svc)] \(.msg)"' \
"$LOG_FILE"
# Count errors per service
echo ""
echo "=== Error count by service ==="
jq -r --arg lvl "$LEVEL" \
'select(.level == $lvl) | .svc' "$LOG_FILE" \
| sort | uniq -c | sort -rnComprobación de conocimientos: comportamiento de select() en jq
Compruebe su comprensión de cómo funciona select() dentro de una canalización de jq.
Dado el siguiente comando:
echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":22}]' | jq '[.[] | select(.age >= 18) | .name]'¿Cuál será la salida?
Resumen de la lección: canalizaciones de jq para filtrar JSON
Ha estudiado las herramientas fundamentales de jq para recorrer y filtrar JSON desde la línea de comandos:
- Notación de punto (
.field,.a.b.c) selecciona campos de objetos - Acceso a arrays (
.[0],.[]) permite indexar y recorrer arrays - Operador de tubería (
|) encadena filtros; cada etapa procesa todos los valores de la anterior - select(cond) filtra valores y solo deja pasar aquellos cuya condición sea verdadera
- Construcción de objetos y arrays (
{},[],map()) remodela los datos en nuevas estructuras - Operador alternativo (
//) proporciona valores predeterminados para campos nulos o inexistentes - Indicador -r elimina las comillas al asignar variables del shell; --arg inserta variables del shell de forma segura
- Descenso recursivo (
.. | .field?) busca en árboles profundamente anidados cuando se desconoce la ruta
Con estos elementos puede transformar cualquier respuesta de una API JSON, archivo de registro o configuración en exactamente los datos que necesitan sus scripts, sin salir del terminal.
Preguntas frecuentes
¿La lección «Filtrado y selección de JSON con pipelines de jq» es gratis?
Sí — el texto completo de «Filtrado y selección de JSON con pipelines de jq» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Linux Command Line & Bash Scripting Mastery, actualiza a CoddyKit PRO. El curso de Linux Command Line & Bash Scripting Mastery incluye 4 lecciones en total.
¿Qué aprenderé en «Filtrado y selección de JSON con pipelines de jq»?
Navegue por objetos y arrays anidados mediante selectores, tuberías y el filtro select de jq. Practicas Linux Command Line & Bash Scripting Mastery con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Linux Command Line & Bash Scripting Mastery?
No se requiere experiencia previa. Linux Command Line & Bash Scripting Mastery en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Filtrado y selección de JSON con pipelines de jq»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Linux Command Line & Bash Scripting Mastery?
Sí. Cada lección de Linux Command Line & Bash Scripting Mastery incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Filtrado y selección de JSON con pipelines de jq
- Transformación y construcción de objetos JSON con jq
- Consumo conjunto de API REST con curl y jq
- Edición de archivos de configuración YAML con yq