Formatear JSON en Bash con jq — Guía y Validación

·SRE & Shell Scripting Specialist·Revisado porErik Lindqvist·Publicado

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.

PUNTOS CLAVE
  • jq . formatea Y valida simultáneamente — sale con código 1 en JSON inválido
  • • Usa jq -e en 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.tool funciona 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.

Before · json
After · json
{"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

Bash
# 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

Bash
# 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.json

Escribir la salida formateada en un archivo

Bash
# Guardar la salida formateada (NO redirigir al mismo archivo)
jq . compact.json > formatted.json

# Compacto (minificar) — inverso del formateo
jq -c . formatted.json
Nota: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

Bash
# 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:

Opción
Tipo
Predeterminado
Descripción
.
filtro
Filtro de identidad — formatea e imprime el input completo sin modificarlo.
--indent N
int
2
Establece la indentación en N espacios (0–7). Usa 2 o 4 para el formato estándar.
--tab
flag
off
Indenta con un carácter de tabulación en lugar de espacios.
-c / --compact-output
flag
off
Colapsa la salida en una sola línea (minifica). Revierte el pretty-print.
-r / --raw-output
flag
off
Imprime strings sin comillas JSON. Útil para extraer valores de texto plano.
-e / --exit-status
flag
off
Sale con código 1 si la salida es false o null. Ideal para aserciones en CI.
-M / --monochrome-output
flag
off
Desactiva la salida en color — útil al redirigir a archivos o destinos no terminales.
-S / --sort-keys
flag
off
Ordena todas las claves de objetos alfabéticamente en cada nivel de anidamiento.
-n / --null-input
flag
off
No lee input; se usa con --arg / --argjson para construir JSON desde cero.
--arg name val
string
Vincula un string de shell como variable jq con nombre ($name) accesible en el filtro.

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

Bash
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

Bash
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

Bash
find ./config -name "*.json" | while read -r f; do
  jq . "$f" > /dev/null 2>&1 || echo "INVÁLIDO: $f"
done
Nota:El flag -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

Bash
# 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

Bash
# 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

Bash
# 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

YAML
- 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

Bash
#!/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"
Nota:Guarda el hook pre-commit en 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

Bash
# 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

Bash
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"
Nota:--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.

Bash
# 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
Aviso: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.
Bash
# 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álido

Salida 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

Bash
# 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

Bash
# 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

Bash
# -C fuerza el color aunque stdout no sea un tty (p. ej., al canalizar a less)
jq -C . logs/deploy-response.json | less -R
Aviso:Usa la salida en color (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

Bash
# --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

Bash
# 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
Bash
# 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.ndjson
Nota:Cambia de jq . 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

Sobrescribir el archivo fuente con redirección shell

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.

Before · Bash
After · Bash
jq --indent 2 . settings.json > settings.json
tmp=$(mktemp) && jq --indent 2 . settings.json > "$tmp" && mv "$tmp" settings.json
No manejar el fallo de jq en scripts

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.

Before · Bash
After · Bash
jq . response.json > formatted.json
jq . response.json > formatted.json || { echo "JSON inválido en response.json" >&2; exit 1; }
Olvidar -s con curl

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.

Before · Bash
After · Bash
curl https://api.payments.internal/config | jq .
curl -s https://api.payments.internal/config | jq .
Usar jq -r . esperando JSON formateado

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.

Before · Bash
After · Bash
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:

Tool
Valida
Coloriza
Apto para CI
Códigos de salida
Control de indentación
Install
jq
✅ (código 1)
✅ --indent N
brew / apt / dnf
python3 -m json.tool
✅ (estricto)
✅ (código 1)
✅ --indent N
Incluido (Python)
json_pp (Perl)
⚠️ parcial
⚠️ variable
Incluido (Perl)
fx (Node.js)
⚠️ parcial
⚠️ limitado
npm install -g fx
node -e JSON.parse
✅ JSON.stringify
Incluido (Node.js)

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.

Bash
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.

Bash
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.

Bash
# 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.

Bash
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.

Bash
# 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.

Bash
# 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: 1

Herramientas 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:

También disponible en:PythonGoJavaScript
NO
Nadia OkonkwoSRE & Shell Scripting Specialist

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.

EL
Erik LindqvistRevisor técnico

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.