Formatear JSON en Bash con jq — Guía y Validación
Usa el Formateador y Embellecedor JSON gratuito directamente en tu navegador — sin instalación.
Probar Formateador y Embellecedor JSON online →Cuando un script de despliegue comienza a procesar respuestas de API o a validar archivos de configuración en CI, saber cómo formatear JSON en bash se vuelve rápidamente esencial. Las dos herramientas que cubren el 99% de los casos del mundo real son jq y python3 -m json.tool — ambas pueden manejar pipelines de format json bash de forma fiable, validar con códigos de salida e integrarse limpiamente en flujos de trabajo CI/CD. Para inspecciones puntuales sin terminal, el Formateador JSON basado en el navegador lo resuelve al instante. Esta guía cubre la instalación de jq, el formateo desde pipes y archivos, funciones de validación, integración CI/CD en GitHub Actions, hooks pre-commit, patrones heredoc y cuándo recurrir al fallback de la stdlib de Python.
- •
jq .formatea Y valida simultáneamente — sale con código 1 en JSON inválido - • Usa
jq -een pipelines de CI: salida distinta de cero en output vacío/false/null - •
jq . file.json > /dev/null && echo "valid"— valida sin modificar la salida - •
python3 -m json.toolfunciona en cualquier sistema sin instalación adicional - • Nunca hagas
jq . f.json > f.json— el shell trunca el archivo fuente antes de que jq lo lea
¿Qué es el formateo de JSON en Bash?
El formateo de JSON en bash consiste en transformar JSON compacto y minificado en una salida indentada y legible por humanos. Los datos subyacentes no cambian — solo difieren los espacios en blanco y los saltos de línea. En contextos de scripting esto importa por dos razones: legibilidad al depurar, y validación cuando el formateador comprueba la sintaxis como efecto secundario. Herramientas como jq analizan el JSON completamente antes de reformatearlo, lo que significa que una ejecución exitosa de formateo es también una verificación implícita de validez. Ese comportamiento dual — formatear y validar en un solo paso — es lo que hace que jq sea tan útil en pipelines automatizados.
{"service":"payments-api","version":"2.4.1","database":{"host":"db-prod-01.internal","port":5432,"pool_size":20},"cache":{"enabled":true,"ttl":300}}{
"service": "payments-api",
"version": "2.4.1",
"database": {
"host": "db-prod-01.internal",
"port": 5432,
"pool_size": 20
},
"cache": {
"enabled": true,
"ttl": 300
}
}jq — Formatear JSON en Bash
jq es el estándar de facto para el procesamiento de JSON en scripts de shell (jq 1.6+, bash 4+). Es un procesador JSON de línea de comandos diseñado específicamente para formatear, filtrar, transformar y validar JSON. El filtro de identidad . pasa el input sin modificaciones, pero formateado. Cuando jq no puede analizar el input sale con código 1 — esto es lo que lo hace ideal para scripting: el formateo y la validación son una sola operación.
Instalar jq
# macOS brew install jq # Debian / Ubuntu apt-get install -y jq # Fedora / RHEL / CentOS dnf install jq # Alpine (imágenes Docker) apk add --no-cache jq # Verificar jq --version # jq-1.7.1
Formatear desde stdin y desde un archivo
# Canalizar JSON inline a través de jq
echo '{"host":"db-prod-01.internal","port":5432}' | jq .
# Formatear un archivo directamente (imprime en stdout)
jq . config/feature-flags.json
# Formatear con indentación de 4 espacios
jq --indent 4 . config/feature-flags.json
# Formatear usando tabulaciones en lugar de espacios
jq --tab . config/feature-flags.jsonEscribir la salida formateada en un archivo
# Guardar la salida formateada (NO redirigir al mismo archivo) jq . compact.json > formatted.json # Compacto (minificar) — inverso del formateo jq -c . formatted.json
jq sale con código 1 en JSON inválido, código 0 en éxito, y código 5 en errores de uso. Úsalo en sentencias if y guardias || exit 1 a lo largo de tus scripts.Ordenar claves y eliminar color
# Ordenar todas las claves alfabéticamente (útil para diffs deterministas) jq --sort-keys . config/app-config.json # Desactivar la salida en color al escribir en un archivo de log jq --monochrome-output . response.json >> deploy.log
Referencia de Opciones de jq
Los flags de jq más utilizados para flujos de trabajo de formateo y validación:
Validar JSON en un Script Bash
La validación y el formateo son la misma operación en jq — analiza antes de imprimir. Redirige stdout a /dev/null cuando solo quieres el código de salida sin la salida formateada. El patrón a continuación es reutilizable en scripts de despliegue, hooks pre-commit y pipelines de CI. En respuesta a incidentes, lo primero que hago con un payload de API desconocido es canalizarlo a través de jq — convierte una pared de JSON minificado en algo que puedo leer y depurar realmente.
Función de validación reutilizable
validate_json() {
local file="$1"
if jq . "$file" > /dev/null 2>&1; then
echo "✓ JSON válido: $file"
return 0
else
echo "✗ JSON inválido: $file" >&2
return 1
fi
}Abortar un despliegue en configuración inválida
CONFIG="infra/k8s/app-config.json"
validate_json "$CONFIG" || { echo "Abortando despliegue: configuración inválida" >&2; exit 1; }Validar todos los archivos JSON en un directorio
find ./config -name "*.json" | while read -r f; do jq . "$f" > /dev/null 2>&1 || echo "INVÁLIDO: $f" done
-e / --exit-status va más lejos: también sale con código 1 cuando la salida es false o null. Úsalo para afirmar que un campo específico es verdadero: jq -e '.feature_flags.new_checkout' config.json.Formatear JSON desde Archivos y Respuestas de API
Dos fuentes comunes de JSON en scripts de shell son los archivos en disco y las respuestas HTTP de API a través de curl. Cada una tiene un patrón de manejo ligeramente diferente. Para archivos, la principal preocupación es la edición segura en el lugar. Para respuestas de API, el detalle clave es suprimir la barra de progreso de curl para que no corrompa el input de jq.
Formateo seguro en el lugar de un archivo
# Formatear y sobrescribir de forma segura usando un archivo temporal tmp=$(mktemp) jq --indent 2 . config/feature-flags.json > "$tmp" && mv "$tmp" config/feature-flags.json echo "Formateado config/feature-flags.json"
Formatear una respuesta de API con curl
# Formatear el estado de despliegue desde la API DEPLOY_ID="dep_8f3a2b9c" curl -s \ -H "Authorization: Bearer $DEPLOY_API_TOKEN" \ "https://api.deployments.internal/v1/deploys/$DEPLOY_ID" \ | jq --indent 2 .
Formatear y filtrar simultáneamente
# Obtener formateado + filtrar solo errores desde un endpoint de monitoreo
curl -s "https://monitoring.internal/api/events?level=error&limit=10" \
| jq '[.events[] | {id, message, timestamp, service}]' \
|| { echo "Error al obtener o analizar eventos" >&2; exit 1; }El patrón || { ... } es crítico aquí. Sin él, un curl fallido o una respuesta de API malformada pasa silenciosamente y el siguiente paso de tu script opera con datos vacíos o parciales. Si necesitas inspeccionar respuestas anidadas complejas sin escribir primero una expresión de filtro, el Formateador JSON basado en el navegador te permite pegar la respuesta sin procesar y navegar por el árbol de forma interactiva.
Formatear JSON en Pipelines CI/CD
CI es donde más importan las puertas de validación de JSON — una configuración malformada que llega a producción es mucho más dolorosa de revertir que un fallo en el pipeline. La mayoría de los competidores documentan jq para uso terminal puntual; los patrones a continuación son los que uso en flujos de trabajo SRE en producción para detectar errores de configuración antes de que lleguen a un slot de despliegue.
GitHub Actions — validar todas las configuraciones JSON
- name: Validar configuraciones JSON
run: |
echo "Validando archivos de configuración JSON..."
find . -name "*.json" -not -path "*/node_modules/*" | while read -r f; do
if ! jq . "$f" > /dev/null 2>&1; then
echo "::error file=$f::Sintaxis JSON inválida"
exit 1
fi
done
echo "Todos los archivos JSON son válidos"Hook pre-commit — validar archivos JSON en staging
#!/usr/bin/env bash
set -euo pipefail
STAGED=$(git diff --cached --name-only --diff-filter=ACM | grep '\.json$' || true)
[ -z "$STAGED" ] && exit 0
for f in $STAGED; do
jq . "$f" > /dev/null 2>&1 || { echo "JSON inválido: $f"; exit 1; }
done
echo "Validación JSON superada"scripts/validate-json.sh, hazlo ejecutable con chmod +x scripts/validate-json.sh, luego crea un enlace simbólico: ln -s ../../scripts/validate-json.sh .git/hooks/pre-commit.Formatear Variables JSON y Heredocs en Bash
Los scripts de shell a menudo construyen payloads JSON dinámicamente — a partir de variables de entorno, metadatos de git o valores calculados. El patrón más seguro es jq -n --arg / --argjson en lugar de interpolación de strings, que se rompe en el momento en que un valor contiene una comilla o un salto de línea. Siempre pon entre comillas dobles las variables cuando las canalices a jq para evitar la división de palabras en espacios en blanco del JSON.
Formatear una variable con respuesta de API almacenada
# Siempre entrecomilla "$API_RESPONSE" — los espacios en JSON romperían una expansión sin comillas echo "$API_RESPONSE" | jq --indent 2 .
Construir y formatear un payload con jq -n
payload=$(jq -n \
--arg env "production" \
--arg version "$(git describe --tags)" \
--argjson replicas 3 \
'{environment: $env, version: $version, replicas: $replicas}')
# Inspeccionar el payload construido
echo "$payload" | jq .
# Enviarlo a una API
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DEPLOY_API_TOKEN" \
-d "$payload" \
"https://api.deployments.internal/v1/deploys"--arg siempre vincula un valor de string. --argjson analiza el valor como JSON primero, por lo que puedes pasar números, booleanos, arrays y objetos sin entrecomillarlos dentro de la expresión de filtro.Formatear JSON en Bash Sin Instalar jq
Cuando jq no está disponible — imágenes Docker mínimas, runners de CI restringidos o sistemas donde no puedes instalar paquetes — el módulo json.tool integrado de Python proporciona la misma capacidad básica. Es parte de la biblioteca estándar de Python; si Python 3 está instalado, funciona sin dependencias adicionales.
# Formatear desde un archivo python3 -m json.tool config.json # Controlar el ancho de indentación python3 -m json.tool --indent 2 config.json # Ordenar claves alfabéticamente python3 -m json.tool --sort-keys config.json # Formatear desde stdin (p. ej., canalizado desde curl) curl -s https://api.deployments.internal/v1/status | python3 -m json.tool
python3 -m json.tool es más estricto que jq: rechaza comas finales, comentarios y extensiones JSON5. Esta estrictitud es deseable para la validación de configuraciones en producción, pero puede ser un punto de fricción al trabajar con JSON laxo de herramientas de terceros. Tampoco produce salida coloreada, lo que hace que la inspección en terminal sea menos ergonómica que jq para uso interactivo.# Validación con código de salida (misma semántica que jq)
python3 -m json.tool config.json > /dev/null && echo "válido" || echo "inválido"
# Validación de string inline
echo '{"service":"payments-api","healthy":true}' | python3 -m json.tool > /dev/null
echo "Código de salida: $?" # 0 = válidoSalida en Terminal con Resaltado de Sintaxis
jq coloriza su salida por defecto — claves en azul, strings en verde, números en blanco. Cuando necesitas resaltado de sintaxis JSON completo en un paginador desplazable, o al depurar respuestas grandes y anidadas en una sesión de terminal, bat proporciona la experiencia más ergonómica. Ambos son útiles para depuración e inspección interactiva; ninguno debería usarse al escribir salidas en archivos o respuestas de API.
Instalar bat
# macOS brew install bat # Debian / Ubuntu (el binario puede llamarse batcat — crea un alias si es así) apt-get install -y bat # alias bat=batcat # añadir a ~/.bashrc si es necesario # Verificar bat --version # bat 0.24.0
Ver archivos JSON con resaltado de sintaxis
# JSON con resaltado de sintaxis en el paginador (pulsa q para salir) bat config/app-config.json # Desactivar el paginador — imprimir directamente en el terminal bat --paging=never config/app-config.json # Canalizar la salida de jq a bat para inspección en color jq '.database' infra/app-config.json | bat --language=json --paging=never
Salida de jq en color en un paginador desplazable
# -C fuerza el color aunque stdout no sea un tty (p. ej., al canalizar a less) jq -C . logs/deploy-response.json | less -R
bat / jq -C) solo para inspección y depuración en terminal. Elimina los códigos de color ANSI antes de escribir en archivos de log o canalizar a otras herramientas — usa jq -M . (--monochrome-output) o bat --plain.Trabajar con Archivos JSON Grandes en Bash
Cuando un archivo JSON supera los 50–100 MB, cargarlo en memoria con el modo predeterminado de jq puede ser lento o desencadenar OOM en hosts con memoria limitada (contenedores Docker con un límite de 512 MB, por ejemplo). jq --stream emite pares ruta/valor de forma incremental a medida que lee, sin almacenar en búfer el documento completo. Para NDJSON (un objeto JSON por línea), jq tiene un enfoque nativo más eficiente.
Transmitir un archivo JSON grande con jq --stream
# --stream emite pares [ruta, escalar] a medida que jq lee el input # Extraer todos los campos "status" de un archivo de log grande sin cargarlo completamente jq -c --stream 'if length == 2 and (.[0][-1] == "status") then .[1] else empty end' logs/archive-2026-03.json
NDJSON / JSON Lines — procesar un objeto por línea
# NDJSON: un objeto JSON por línea — común en exportaciones de Kafka, Fluentd y Logstash
# -R lee líneas en bruto; fromjson? omite las líneas que no son JSON válido
jq -c -R 'fromjson? | {id: .request_id, status: .http_status, latency: .duration_ms}' logs/access-2026-03-13.ndjson > logs/summary.ndjson# Alternativa con bucle shell — útil cuando necesitas manejo de errores por línea
while IFS= read -r line; do
echo "$line" | jq -c '{id: .request_id, status: .http_status}' 2>/dev/null || echo "OMITIR: línea malformada" >&2
done < logs/access-2026-03-13.ndjsonjq . file.json estándar a --stream cuando el archivo supere los 50–100 MB o cuando el proceso se ejecute dentro de un contenedor con límite de memoria. Para pipelines NDJSON, prefiere jq -R 'fromjson?' sobre un bucle while read de shell — es significativamente más rápido porque evita lanzar un subshell por línea.Errores Comunes
Problema: El shell abre y trunca el archivo de salida antes de que jq lea el input. Si el origen y el destino son la misma ruta, jq lee un archivo vacío.
Solución: Escribe primero en un archivo temporal mktemp, luego reemplaza el original de forma atómica con mv.
jq --indent 2 . settings.json > settings.json
tmp=$(mktemp) && jq --indent 2 . settings.json > "$tmp" && mv "$tmp" settings.json
Problema: Sin un manejador de errores, el script continúa silenciosamente con un archivo formateado vacío o inexistente cuando el JSON es inválido — los pasos posteriores fallan entonces con errores confusos.
Solución: Añade || { echo '...' >&2; exit 1; } después de cada llamada a jq que produzca una salida utilizada por un paso posterior.
jq . response.json > formatted.json
jq . response.json > formatted.json || { echo "JSON inválido en response.json" >&2; exit 1; }Problema: curl imprime una barra de progreso en stderr por defecto. Cuando stderr se fusiona con stdout (p. ej., en subshells o captura de logs), el texto de la barra de progreso aparece en el input de jq y provoca un error de análisis.
Solución: Pasa siempre -s (silencioso) a curl cuando canalices a jq. Usa -v o --fail-with-body por separado si necesitas salida de diagnóstico.
curl https://api.payments.internal/config | jq .
curl -s https://api.payments.internal/config | jq .
Problema: El flag -r / --raw-output elimina las comillas JSON de los valores de string de nivel superior — no formatea objetos ni arrays. Pasar -r . a un objeto produce el mismo objeto compacto, no una salida indentada.
Solución: Usa jq . (sin el flag -r) para formatear. Reserva -r para extraer valores de string planos como jq -r '.version' config.json.
jq -r . config.json
jq . config.json
jq vs python3 vs json_pp — Comparación Rápida
La elección entre herramientas depende de lo que esté disponible en tu entorno y de lo que necesites más allá del formateo básico:
Para la mayoría de scripting bash y trabajo CI/CD, jq es el predeterminado correcto — valida, formatea, filtra y proporciona códigos de salida fiables en un único binario sin dependencia de runtime. Recurre a python3 -m json.tool cuando no puedas instalar paquetes adicionales y Python ya esté presente.
Preguntas Frecuentes
¿Cómo formateo un archivo JSON en el lugar usando bash?
Nunca redirijas la salida de jq al mismo archivo — el shell trunca el archivo antes de que jq lo lea. En su lugar, escribe primero en un archivo temporal y luego reemplaza el original de forma atómica con mv.
tmp=$(mktemp) jq --indent 2 . config/app-config.json > "$tmp" && mv "$tmp" config/app-config.json echo "Formateado en el lugar correctamente"
¿Cómo valido JSON en un script bash y salgo en caso de error?
Pasa el archivo a jq y redirige stdout a /dev/null. Usa || para capturar la salida distinta de cero y abortar el script. jq sale con código 1 en cualquier error de análisis, lo que lo hace fiable como puerta de validación en CI.
validate_json() {
local file="$1"
if jq . "$file" > /dev/null 2>&1; then
echo "✓ JSON válido: $file"
return 0
else
echo "✗ JSON inválido: $file" >&2
return 1
fi
}
validate_json infra/k8s/app-config.json || exit 1¿Cómo formateo JSON en bash sin instalar jq?
Usa el módulo json.tool integrado de python3 — viene con cada instalación estándar de Python y produce una salida correctamente indentada con la misma semántica de código de salida que jq.
# Formatear desde un archivo python3 -m json.tool config.json # Formatear desde stdin (p. ej., una respuesta de curl) curl -s https://api.internal/status | python3 -m json.tool --indent 2
¿Cómo formateo JSON desde una respuesta curl en bash?
Pasa siempre -s (silencioso) a curl para que las barras de progreso no corrompan el input de jq. Canaliza el stdout de curl directamente a jq.
DEPLOY_ID="dep_8f3a2b9c" curl -s \ -H "Authorization: Bearer $DEPLOY_API_TOKEN" \ "https://api.deployments.internal/v1/deploys/$DEPLOY_ID" \ | jq --indent 2 .
¿Cómo formateo solo una parte de un archivo JSON usando jq?
Usa una expresión de ruta jq en lugar del filtro de identidad (.) para extraer y formatear un objeto o array anidado. El resultado es en sí mismo JSON formateado.
# Formatear solo el bloque de configuración de la base de datos
jq --indent 2 '.database' infra/app-config.json
# Formatear + filtrar el array de eventos solo al nivel de error
jq '[.events[] | select(.level == "error") | {id, message, service}]' events.json¿Qué código de salida devuelve jq para JSON inválido?
jq sale con código 1 ante cualquier error de análisis y también cuando el flag -e / --exit-status está activo y la salida es false o null. El código de salida 0 significa que se analizó JSON válido con salida verdadera. El código de salida 5 significa que el sistema encontró un error de uso.
# Verificar el código de salida directamente
echo '{"ok":true}' | jq . > /dev/null 2>&1; echo "salida: $?" # salida: 0
echo '{json malo}' | jq . > /dev/null 2>&1; echo "salida: $?" # salida: 1
# flag -e: sale 1 si la salida es false/null
echo 'null' | jq -e . > /dev/null 2>&1; echo "salida: $?" # salida: 1Herramientas Relacionadas
Alternativas y complementos basados en el navegador para el formateo JSON en bash — útiles cuando necesitas una interfaz visual, un enlace compartible o estás trabajando fuera de un terminal:
Nadia is a site reliability engineer who lives in the terminal. She writes Bash scripts that process logs, transform data, and orchestrate infrastructure across fleets of servers. She is a heavy user of jq, awk, and sed and writes about shell one-liners, text processing pipelines, data serialisation from the command line, and the practical Bash patterns that SREs reach for when speed matters more than elegance.
Erik is a DevOps engineer who has spent years writing and maintaining the shell scripts that hold CI/CD pipelines together. He writes about Bash best practices, portable POSIX shell, encoding and decoding in shell scripts, secret management from the command line, and the patterns that separate reliable automation scripts from brittle ones. He is a strong believer in making shell scripts readable and testable with tools like bats-core.