Necesitas extraer campos específicos de una respuesta de API. Parsear un package.json para listar dependencias. Filtrar entradas de error de logs en formato JSON. Todo desde la terminal, sin escribir un script.
Eso es lo que hace jq. Conocido como la navaja suiza del procesamiento JSON, maneja el formateo, filtrado, transformación y agregación de datos JSON — todo en un solo comando.
Esta guía recorre todo, desde filtros básicos hasta ejemplos de scripting del mundo real, con comandos listos para ejecutar.
¿Qué es jq?
jq es un procesador JSON ligero de línea de comandos escrito en C. Se distribuye como un binario único sin dependencias externas.
Características clave:
- Pretty-printing — formatea JSON minificado en una salida legible
- Extracción de campos — obtén exactamente los valores que necesitas
- Filtrado — selecciona datos que cumplan condiciones específicas
- Transformación — reestructura datos y calcula agregados
- Encadenamiento — combina múltiples operaciones en una sola expresión
Así como sed y awk son las herramientas de referencia para el procesamiento de texto, jq es el estándar para JSON. Combinado con curl, es una parte esencial de cualquier kit de herramientas CLI moderno.
Instalación
# winget (recomendado)
winget install jqlang.jq
# Si usas WSL, instala vía el gestor de paquetes de Linux
# sudo apt install jq
Verifica la instalación:
jq --version
jq-1.8.1
Uso básico
Pretty-print de JSON
El filtro más simple es . — toma la entrada y la imprime formateada.
echo '{"name":"test","value":42,"active":true}' | jq '.'
{
"name": "test",
"value": 42,
"active": true
}
Para leer desde un archivo, pasa el nombre del archivo como argumento:
jq '.' data.json
Extraer campos
Usa notación de punto para acceder a campos específicos:
echo '{"name":"jq","version":"1.8.1"}' | jq '.name'
"jq"
Para salida de cadena sin comillas, usa -r (salida raw):
echo '{"name":"jq","version":"1.8.1"}' | jq -r '.name'
jq
Campos anidados
Encadena puntos para acceder a valores profundamente anidados:
echo '{"data":{"users":[{"name":"Alice","age":30}]}}' | jq '.data.users[0].name'
"Alice"
Operaciones con arrays
# Primer elemento
echo '[10,20,30]' | jq '.[0]'
# Último elemento
echo '[10,20,30]' | jq '.[-1]'
# Longitud del array
echo '[10,20,30]' | jq 'length'
# Porción (índice 1 a 2)
echo '[10,20,30,40]' | jq '.[1:3]'
Formato de salida
# Salida compacta (una sola línea)
echo '{"name":"test","value":42}' | jq -c '.'
# Indentación con tabulaciones
echo '{"name":"test","value":42}' | jq --tab '.'
# Claves ordenadas
echo '{"b":2,"a":1}' | jq -S '.'
Filtros y pipes
El verdadero poder de jq reside en combinar filtros. Usa el operador pipe | para encadenar operaciones.
Iterador de arrays
[] expande cada elemento de un array:
echo '{"users":[{"name":"Alice"},{"name":"Bob"},{"name":"Charlie"}]}' \
| jq '.users[].name'
"Alice"
"Bob"
"Charlie"
select — filtrado condicional
select() mantiene solo los elementos que cumplen una condición:
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25},{"name":"Charlie","age":35}]}' \
| jq '.users[] | select(.age > 28)'
{
"name": "Alice",
"age": 30
}
{
"name": "Charlie",
"age": 35
}
map — transformar arrays
map() aplica un filtro a cada elemento y devuelve un nuevo array:
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
| jq '.users | map(.name)'
[
"Alice",
"Bob"
]
Construcción de objetos
Construye nuevos objetos con solo los campos que necesitas:
echo '{"users":[{"name":"Alice","age":30,"email":"alice@example.com","role":"admin"}]}' \
| jq '.users[] | {name: .name, email: .email}'
{
"name": "Alice",
"email": "alice@example.com"
}
Interpolación de cadenas
Usa \() para incrustar valores en cadenas. Combina con -r para salida limpia:
echo '{"users":[{"name":"Alice","email":"alice@example.com"},{"name":"Bob","email":"bob@example.com"}]}' \
| jq -r '.users[] | "\(.name): \(.email)"'
Alice: alice@example.com
Bob: bob@example.com
Expresiones condicionales
echo '{"status":"ok","data":"hello"}' \
| jq 'if .status == "ok" then .data else "error: \(.status)" end'
"hello"
Ordenación, agrupación y agregación
# Ordenar por campo
echo '[{"name":"Charlie","age":35},{"name":"Alice","age":30},{"name":"Bob","age":25}]' \
| jq 'sort_by(.age)'
# Valores únicos
echo '["apple","banana","apple","cherry","banana"]' | jq 'unique'
# Suma
echo '[10,20,30,40]' | jq 'add'
# Promedio
echo '[10,20,30,40]' | jq 'add / length'
keys y has
# Listar todas las claves
echo '{"name":"test","version":"1.0","license":"MIT"}' | jq 'keys'
# Verificar si existe una clave
echo '{"name":"test"}' | jq 'has("name")'
Casos de uso reales
Procesar respuestas de API
Combinar jq con curl para extraer datos de respuestas de API es uno de los casos de uso más comunes.
curl -s https://api.github.com/repos/jqlang/jq \
| jq '{name: .name, stars: .stargazers_count, forks: .forks_count, license: .license.spdx_id}'
{
"name": "jq",
"stars": 31000,
"forks": 1600,
"license": "MIT"
}
Combinar resultados de respuestas paginadas de API:
for page in 1 2 3; do
curl -s "https://api.github.com/users/octocat/repos?per_page=100&page=${page}"
done | jq -s 'flatten | map({name: .name, stars: .stargazers_count}) | sort_by(.stars) | reverse'
Parsear package.json
Inspecciona rápidamente las dependencias del proyecto sin abrir el archivo:
# Listar nombres de dependencias
jq '.dependencies | keys' package.json
[
"next",
"react",
"react-dom"
]
# Mostrar paquetes con versiones
jq -r '.dependencies | to_entries[] | "\(.key)@\(.value)"' package.json
next@^16.0.0
react@^19.0.0
react-dom@^19.0.0
# Contar dependencies vs devDependencies
jq '{deps: (.dependencies | length), devDeps: (.devDependencies | length)}' package.json
Análisis de logs JSON
Procesar archivos de log en formato JSON Lines (un objeto JSON por línea):
# Extraer logs de error con marcas de tiempo
cat app.log \
| jq -r 'select(.level == "error") | "\(.timestamp) [\(.level)] \(.message)"'
2026-03-08T10:15:30Z [error] Database connection timeout
2026-03-08T10:18:45Z [error] Failed to process request
# Contar entradas por nivel de log
cat app.log \
| jq -s 'group_by(.level) | map({level: .[0].level, count: length})'
[
{ "level": "error", "count": 5 },
{ "level": "info", "count": 142 },
{ "level": "warn", "count": 23 }
]
Editar archivos de configuración
Modifica archivos de configuración JSON desde la línea de comandos:
# Actualizar un valor
jq '.database.port = 5433' config.json > tmp.json && mv tmp.json config.json
# Añadir un campo
jq '.database.ssl = true' config.json > tmp.json && mv tmp.json config.json
# Eliminar un campo
jq 'del(.debug)' config.json > tmp.json && mv tmp.json config.json
# Fusionar dos archivos JSON (el override tiene precedencia)
jq -s '.[0] * .[1]' base.json override.json > merged.json
Ejemplos de scripting
Exportar repos de GitHub a CSV
#!/bin/bash
# github-repos-to-csv.sh
# Exportar los repositorios públicos de un usuario a formato CSV
USERNAME="${1:?Uso: $0 <github-username>}"
OUTPUT="repos.csv"
echo "name,stars,forks,language,updated" > "${OUTPUT}"
page=1
while true; do
response=$(curl -s "https://api.github.com/users/${USERNAME}/repos?per_page=100&page=${page}")
count=$(echo "${response}" | jq 'length')
if [ "${count}" -eq 0 ]; then
break
fi
echo "${response}" \
| jq -r '.[] | [.name, .stargazers_count, .forks_count, (.language // "N/A"), .updated_at[:10]] | @csv' \
>> "${OUTPUT}"
page=$((page + 1))
done
total=$(tail -n +2 "${OUTPUT}" | wc -l)
echo "Exportados ${total} repositorios a ${OUTPUT}"
Puntos clave:
- El filtro
@csvmaneja el formateo CSV automáticamente, incluyendo comillas y escape // "N/A"es el operador alternativo — devuelve un valor por defecto cuando un valor esnull- La paginación se gestiona con un bucle simple hasta obtener una respuesta vacía
Fusionar y agregar informes JSON
#!/bin/bash
# merge-json-reports.sh
# Combinar archivos de informes JSON y generar estadísticas resumen
REPORT_DIR="${1:?Uso: $0 <directorio-de-informes>}"
if [ ! -d "${REPORT_DIR}" ]; then
echo "Error: Directorio '${REPORT_DIR}' no encontrado" >&2
exit 1
fi
file_count=$(find "${REPORT_DIR}" -name "*.json" -type f | wc -l)
if [ "${file_count}" -eq 0 ]; then
echo "Error: No se encontraron archivos JSON en '${REPORT_DIR}'" >&2
exit 1
fi
# Fusionar todos los archivos JSON y calcular resumen
find "${REPORT_DIR}" -name "*.json" -type f -exec cat {} + \
| jq -s '{
total_files: length,
total_records: (map(.records // 0) | add),
total_errors: (map(.errors // 0) | add),
avg_duration_ms: (map(.duration_ms // 0) | add / length | floor),
statuses: (group_by(.status) | map({status: .[0].status, count: length})),
date_range: {
earliest: (map(.timestamp) | sort | first),
latest: (map(.timestamp) | sort | last)
}
}'
echo ""
echo "Procesados ${file_count} archivos de ${REPORT_DIR}"
Puntos clave:
-s(slurp) combina múltiples objetos JSON en un solo arraygroup_byymapjuntos producen conteos por estado// 0proporciona valores de respaldo para campos ausentesfloortrunca los decimales en el promedio
Nota de seguridad
Al procesar JSON no confiable, ten en cuenta estos puntos:
- Mantén jq actualizado — las vulnerabilidades del parser se descubren periódicamente. Si
jq --versionmuestra algo por debajo de 1.8.1, actualiza inmediatamente - Limita el tamaño de entrada — procesar archivos JSON muy grandes puede consumir mucha memoria. Usa
head -cantes en el pipeline para limitar el tamaño de entrada, o considera el parser streaming (--stream) para conjuntos de datos grandes - Protégete contra inyección de shell — nunca canalices la salida de jq directamente a
evalobash -c. Siempre captura los valores en variables entre comillas
# Peligroso (nunca hagas esto)
eval $(curl -s https://example.com/config.json | jq -r '.command')
# Seguro (capturar en una variable)
value=$(curl -s https://example.com/config.json | jq -r '.setting')
echo "Configuración: ${value}"
Conclusión
jq es la herramienta esencial para el procesamiento de JSON en la línea de comandos.
- Básico —
.para pretty-printing,.campopara extracción,-rpara salida de cadenas sin comillas - Filtros —
selectpara filtrado condicional,mappara transformación, pipes para encadenar - Mundo real — procesamiento de respuestas de API, edición de archivos de configuración, análisis de logs
- Scripting — conversión con
@csv,-spara fusionar, integración con scripts de shell
Combina curl para la obtención de datos, jq para el procesamiento JSON y sed & awk para el formateo de texto — y tendrás un potente pipeline de procesamiento de datos directamente en tu terminal. Empieza con curl ... | jq '.' y construye desde ahí.
Para una visión más amplia de herramientas CLI, consulta el Kit de herramientas CLI.