Skip to content
Volver al blog
Tutoriales

jq Cheat Sheet: 30 patrones JSON reales para línea de comandos

Domina jq con 30 patrones probados para filtrar, transformar y extraer JSON en la línea de comandos — de kubectl y AWS CLI a logs.

12 min de lectura

jq Cheat Sheet: 30 patrones JSON reales para línea de comandos

Pipeas kubectl get pods -o json a less y la terminal se congela ante dos megabytes de JSON. Lo único que quieres es el nombre de cada pod en fase Running. jq lo hace con tres caracteres de filtro — una vez que conoces el vocabulario.

Esto no es otra referencia de sintaxis. Son 30 patrones que realmente vas a teclear, agrupados por la tarea que intentas resolver: acceder, filtrar, transformar, agregar, formatear y combinar con herramientas reales como kubectl, aws y docker.

Cuándo usar jq, el formateador del navegador o código

jq no siempre es la respuesta correcta. Las tres opciones honestas son:

SituaciónMejor herramientaPor qué
Una respuesta de API, necesitas resaltado de sintaxis y números de líneaJSON Formatter en el navegadorDiff visual, cero configuración, privado en el navegador
Pipeline de shell, procesamiento de logs, script de CI, servidor remotojqComponible, guionable, sin dependencia de GUI
Lógica de negocio, pruebas unitarias, bifurcaciones complejasCódigo (JS / Python)Depurador real, tipos, bibliotecas

Elige jq cuando la tarea vive dentro de un pipeline de shell — el resto probablemente sea más sencillo en otro lugar.

Instalación y tu primer pipeline

jq viene como binario único en todas las plataformas principales:

# macOS
brew install jq

# Debian / Ubuntu
sudo apt install jq

# Windows (winget)
winget install jqlang.jq

Un primer pipeline, con el filtro identidad:

curl -s https://api.github.com/users/octocat | jq .

El filtro . toma la entrada y la emite sin cambios, formateada. Solo con eso reemplazas la mayoría de los momentos de «déjame abrir este JSON en un editor».

Cinco flags cubren el 90 % del uso real:

FlagPropósito
-rSalida cruda — quita las comillas alrededor de resultados de tipo string
-cCompacto — un valor JSON por línea (NDJSON)
-sSlurp — lee todas las entradas en un único array
-REntrada cruda — lee líneas como cadenas en vez de JSON
-nEntrada nula — no lee stdin, usa null como entrada

El modelo mental central: filtros y pipes

Un filtro recibe un valor JSON como entrada y produce cero o más valores JSON como salida. Los filtros se componen con un pipe |, que envía cada salida del filtro izquierdo como entrada al filtro derecho. Es el mismo modelo mental que los pipes de shell, solo que fluyen valores JSON en vez de bytes.

# . — identidad
echo '{"name":"Alice"}' | jq '.'

# .key — acceso a un campo
echo '{"name":"Alice"}' | jq '.name'

# .key.sub — ruta profunda
echo '{"user":{"email":"a@x.com"}}' | jq '.user.email'

# .[] — iterar elementos del array (produce múltiples salidas)
echo '[{"id":1},{"id":2}]' | jq '.[] | .id'

# Composición con pipe: cada salida de .items[] alimenta a .name
echo '{"items":[{"name":"a"},{"name":"b"}]}' | jq '.items[] | .name'

Toda la gramática cabe ahí. Los 30 patrones siguientes son combinaciones de estas primitivas.

30 patrones que realmente usarás

Cada patrón muestra JSON de entrada, el comando y la salida. Copia cualquiera directamente a tu terminal.

Acceso y extracción (patrones 1–5)

Patrón 1 — Acceso seguro con ?

Acceder a un campo que podría no existir sin romper:

echo '{"name":"Alice"}' | jq '.address?.city?'
# Salida: null

El ? suprime los errores en claves ausentes. Sin él, .address.city lanzaría un error de tipo si .address no existe.

Patrón 2 — Acceso por ruta profunda

echo '{"user":{"profile":{"email":"a@x.com"}}}' | jq '.user.profile.email'
# Salida: "a@x.com"

Patrón 3 — Slicing de arrays

echo '[10,20,30,40,50]' | jq '.[1:3]'
# Salida: [20, 30]

echo '[10,20,30,40,50]' | jq '.[-1]'
# Salida: 50

Los índices negativos cuentan desde el final. Las rebanadas usan intervalos semiabiertos, como en Python.

Patrón 4 — Descenso recursivo para encontrar cada clave coincidente

echo '{"a":{"name":"x"},"b":[{"name":"y"},{"id":1}]}' | jq '.. | .name? | select(. != null)'
# Salida: "x"
#         "y"

.. recorre cada valor del árbol. Combinado con .name? y select, extrae cada campo name sin importar su profundidad — invaluable para explorar esquemas JSON desconocidos.

Patrón 5 — Listar todas las claves de un objeto

echo '{"zebra":1,"apple":2,"mango":3}' | jq 'keys'
# Salida: ["apple", "mango", "zebra"]

echo '{"zebra":1,"apple":2,"mango":3}' | jq 'keys_unsorted'
# Salida: ["zebra", "apple", "mango"]

keys ordena alfabéticamente; keys_unsorted preserva el orden de inserción.

Filtrar (patrones 6–10)

Patrón 6 — Filtrar un array por condición

echo '[{"age":20},{"age":30},{"age":40}]' | jq 'map(select(.age > 25))'
# Salida: [{"age":30},{"age":40}]

map(f) aplica f a cada elemento; select(cond) conserva solo los elementos donde la condición es verdadera.

Patrón 7 — Coincidencia de prefijo de cadena

echo '[{"name":"api-gateway"},{"name":"web-ui"},{"name":"api-auth"}]' \
  | jq '.[] | select(.name | startswith("api"))'
# Salida: {"name":"api-gateway"}
#         {"name":"api-auth"}

También útiles: endswith("..."), contains("..."), test("^regex$").

Patrón 8 — Condiciones combinadas

echo '[{"type":"A","count":5},{"type":"A","count":15},{"type":"B","count":20}]' \
  | jq '.[] | select(.type == "A" and .count > 10)'
# Salida: {"type":"A","count":15}

and, or, not se comportan como esperarías.

Patrón 9 — Eliminar campos sensibles

echo '{"user":"alice","password":"s3cret","token":"abc"}' | jq 'del(.password, .token)'
# Salida: {"user":"alice"}

del() acepta múltiples rutas y no falla si alguna está ausente.

Patrón 10 — Deduplicar por campo

echo '[{"id":1,"v":"a"},{"id":2,"v":"b"},{"id":1,"v":"a2"}]' | jq 'unique_by(.id)'
# Salida: [{"id":1,"v":"a"},{"id":2,"v":"b"}]

unique deduplica valores completos; unique_by(f) deduplica por el resultado de un filtro.

Transformar (patrones 11–15)

Patrón 11 — Renombrar campos

echo '[{"first_name":"Alice","age":30}]' | jq 'map({name: .first_name, age})'
# Salida: [{"name":"Alice","age":30}]

La forma corta {age} equivale a {age: .age}.

Patrón 12 — Añadir un campo calculado con interpolación de cadena

echo '[{"first":"Alice","last":"Chen"}]' \
  | jq 'map(. + {fullName: "\(.first) \(.last)"})'
# Salida: [{"first":"Alice","last":"Chen","fullName":"Alice Chen"}]

\(expr) evalúa expr e interpola su valor dentro de la cadena.

Patrón 13 — Aplanar arrays anidados

echo '[{"tags":["a","b"]},{"tags":["c"]}]' | jq '[.[] | .tags[]]'
# Salida: ["a","b","c"]

echo '[[1,2],[3,[4,5]]]' | jq 'flatten'
# Salida: [1,2,3,4,5]

flatten acepta un argumento de profundidad: flatten(1) solo quita un nivel.

Patrón 14 — Objeto a array y viceversa

echo '{"a":1,"b":2}' | jq 'to_entries'
# Salida: [{"key":"a","value":1},{"key":"b","value":2}]

echo '[{"key":"a","value":1},{"key":"b","value":2}]' | jq 'from_entries'
# Salida: {"a":1,"b":2}

Este par habilita transformaciones que requieren iterar sobre las claves de un objeto — algo que la sintaxis de puntos no permite directamente.

Patrón 15 — Fusión profunda de dos objetos

echo '{"a":{"x":1},"b":2}' | jq '. * {a:{y:9}, c:3}'
# Salida: {"a":{"x":1,"y":9},"b":2,"c":3}

El operador * hace fusión profunda. Para fusión superficial usa + (el lado derecho gana).

Agregar (patrones 16–20)

Patrón 16 — Longitud de arrays, objetos y cadenas

echo '[1,2,3,4]' | jq 'length'      # 4
echo '{"a":1,"b":2}' | jq 'length'  # 2
echo '"hello"' | jq 'length'        # 5

Patrón 17 — Suma de un campo

echo '[{"price":10},{"price":25},{"price":5}]' | jq '[.[].price] | add'
# Salida: 40

add suma números, concatena cadenas o fusiona arrays — según el tipo de entrada.

Patrón 18 — Agrupar por campo

echo '[{"cat":"A","n":1},{"cat":"B","n":2},{"cat":"A","n":3}]' | jq 'group_by(.cat)'
# Salida: [[{"cat":"A","n":1},{"cat":"A","n":3}],[{"cat":"B","n":2}]]

Cada grupo se convierte en un array interno. Combina con map para agregar por grupo.

Patrón 19 — Ordenar descendente

echo '[{"date":"2026-01-03"},{"date":"2026-01-01"},{"date":"2026-01-02"}]' \
  | jq 'sort_by(.date) | reverse'
# Salida: [{"date":"2026-01-03"},{"date":"2026-01-02"},{"date":"2026-01-01"}]

Las cadenas de fecha ISO 8601 se ordenan correctamente como cadenas. Para otros formatos hay que parsear primero — la guía del timestamp Unix cubre en detalle epoch segundos, milisegundos y conversión de zona horaria.

Patrón 20 — Máximo o mínimo por campo

echo '[{"name":"a","rating":4.1},{"name":"b","rating":4.8},{"name":"c","rating":3.9}]' \
  | jq 'max_by(.rating)'
# Salida: {"name":"b","rating":4.8}

min_by, max_by devuelven un solo elemento. Para el top N usa sort_by(.rating) | reverse | .[:N].

Formatear la salida (patrones 21–25)

Patrón 21 — Salida CSV

echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' \
  | jq -r '.[] | [.name, .age] | @csv'
# Salida: "Alice",30
#         "Bob",25

@csv entrecomilla las cadenas y escapa las comillas internas. -r quita las comillas exteriores del JSON para que el CSV sea directamente pipeable. Para el ida y vuelta completo entre CSV y JSON en un pipeline, consulta la guía de conversión CSV a JSON.

Patrón 22 — Salida TSV

echo '[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]' \
  | jq -r '.[] | [.id, .name] | @tsv'
# Salida: 1	Alice
#         2	Bob

La salida separada por tabuladores encaja bien con cut, awk y column -t.

Patrón 23 — Salida de cadena cruda

echo '["alpha","beta"]' | jq -r '.[]'
# Salida: alpha
#         beta

Sin -r, cada línea llevaría comillas. La salida cruda es la que alimentas a xargs, while read u otro comando de shell.

Patrón 24 — NDJSON / JSON Lines

echo '[{"a":1},{"a":2}]' | jq -c '.[]'
# Salida: {"a":1}
#         {"a":2}

Cada línea es un valor JSON autónomo — el formato que usan Kafka, Elasticsearch y la mayoría de loggers estructurados. -c también quita todo el espacio en blanco interno.

Patrón 25 — Interpolación de cadena para salida formateada

echo '[{"name":"server-1","cpu":0.73},{"name":"server-2","cpu":0.21}]' \
  | jq -r '.[] | "\(.name): \(.cpu * 100)% CPU"'
# Salida: server-1: 73% CPU
#         server-2: 21% CPU

Ideal para resúmenes y líneas de log donde el JSON crudo sería ruido.

DevOps en la práctica (patrones 26–30)

Patrón 26 — kubectl: nombres de cada pod en ejecución

kubectl get pods -o json \
  | jq -r '.items[] | select(.status.phase=="Running") | .metadata.name'

Pipeline: iterar pods, conservar solo Running, emitir el nombre como cadena cruda.

Patrón 27 — AWS EC2: IDs de instancia con IP pública

aws ec2 describe-instances \
  | jq -r '.Reservations[].Instances[] | [.InstanceId, .PublicIpAddress // "none"] | @tsv'

El operador alternativo // aporta un valor de respaldo cuando el campo es null — evita que aparezca un null literal en la columna de salida.

Patrón 28 — API de GitHub: fusionar resultados paginados

for p in 1 2 3; do
  curl -s "https://api.github.com/orgs/myorg/repos?per_page=100&page=$p"
done | jq -s 'add | map(.name)'

-s recoge todas las respuestas en un array de arrays, add las concatena y map(.name) extrae los nombres. Un patrón común para cualquier API paginada.

Patrón 29 — Filtrar archivos de logs estructurados

cat app.log | jq -c 'select(.level=="error")'

Asume que el archivo de log está en NDJSON (un objeto JSON por línea). Combínalo con tail -f para monitoreo en vivo:

tail -f app.log | jq -c 'select(.level=="error") | {ts: .timestamp, msg: .message}'

Patrón 30 — Docker: todos los nombres de imagen en uso

docker inspect $(docker ps -q) | jq -r '.[].Config.Image' | sort -u

Útil para revisar rápido qué versiones de imagen corren en un host.

Errores comunes y cómo resolverlos

Todo usuario de jq se topa con estos. Conocer la solución de antemano ahorra horas.

Cannot iterate over null (null)

El campo de entrada que intentaste iterar era null o estaba ausente. Dos arreglos:

# Opción A: operador opcional
echo '{}' | jq '.items[]?'
# Salida: (nada, sin error)

# Opción B: operador alternativo con valor por defecto
echo '{}' | jq '(.items // [])[]'
# Salida: (nada, sin error)

Usa ? cuando quieras saltar silenciosamente. Usa // [] cuando quieras forzar un array vacío concreto para que los filtros siguientes sigan ejecutándose.

Cannot index array with "key"

Escribiste .foo pero el valor actual es un array. Añade [] para iterar:

# Mal
echo '{"users":[{"name":"Alice"}]}' | jq '.users.name'
# Error: Cannot index array with "name"

# Bien
echo '{"users":[{"name":"Alice"}]}' | jq '.users[].name'
# Salida: "Alice"

Problemas de comillas en shell

Usa comillas simples alrededor del programa jq completo y comillas dobles en su interior para literales de cadena:

# Funciona en todas partes
jq '.users[] | select(.role == "admin")'

# Rompe — las comillas dobles las interpreta el shell primero
jq ".users[] | select(.role == \"admin\")"

Casos límite en PowerShell de Windows

PowerShell no trata las comillas simples del mismo modo. Prefiere comillas dobles alrededor del programa y escapa las internas, o usa una here-string:

jq "@'
.users[] | select(.role == \"admin\")
'@"

Para cualquier cosa no trivial, guarda el filtro en un archivo .jq y ejecuta jq -f filter.jq.

Mal uso de -r

-r solo afecta resultados de tipo cadena. Aplicarlo a un objeto produce un objeto JSON normal:

echo '{"a":1}' | jq -r '.'
# Salida: {"a":1}     ← sin cambios; -r no tenía nada que quitar

Si quieres un campo específico sin comillas, selecciónalo primero: jq -r '.a'.

jq rechaza JSON con comentarios o comas finales

echo '{"a": 1, /* nota */ "b": 2,}' | jq .
# parse error: Invalid numeric literal

jq sigue estrictamente RFC 8259 JSON — sin comentarios, sin comas finales, sin claves sin comillas. Si el archivo es JSON5 o JSONC (común en archivos de configuración), elimina esas extensiones antes de pipeear a jq. La guía de formateo JSON5 y JSONC explica qué parseadores los soportan y cómo convertir a JSON estricto.

jq vs alternativas: gron, fx, jj, yq

jq no es la única opción, y a veces otra herramienta va más rápido:

HerramientaFortalezaCuándo recurrir a ella
gronAplana JSON en rutas grepablesExplorar esquemas desconocidos — no sabes dónde está la clave
fxExplorador TUI interactivo con resaltadoHojear JSON grandes a mano
jjMucho más rápido que jq, sintaxis limitadaBucles intensivos procesando millones de registros
yqMismo lenguaje de filtro pero para YAMLManifiestos de Kubernetes y configuración de CI
JSON Formatter del navegadorResaltado de sintaxis, mensajes de error precisos, sin instalaciónDepurar una respuesta única durante el desarrollo

Para el trabajo diario en shell, jq gana por componibilidad. Para exploración puntual, gron suele ser más rápido. Para YAML, usa yq — no intentes encadenar yq y luego jq.

Consejos pro para el día a día

Algunos hábitos que hacen que jq se sienta natural:

  1. Mantén un .jqrc en $HOME. Pon ahí funciones auxiliares y estarán disponibles en cada invocación de jq:

    def running: select(.status.phase == "Running");
    def table(f): [f] | @tsv;
  2. Usa jqplay.org para filtros complejos. Pega tu JSON a la izquierda, itera el filtro a la derecha, lleva la versión que funciona a tu script.

  3. Construye tu propio cheat sheet desde history. history | grep 'jq ' | sort -u > ~/jq-patterns.txt captura cada patrón que realmente has usado.

  4. Combina con el JSON Formatter del navegador para esquemas desconocidos. Explora la estructura visualmente primero para encontrar la ruta que necesitas, luego escribe el comando jq.

  5. Monitorizar valores en vivo: watch -n 5 "curl -s api.example.com/health | jq '.uptime'" refresca cada 5 segundos — un pequeño dashboard de ops sin dependencias.

FAQ

¿Qué es jq y por qué lo usan los desarrolladores?

jq es un procesador JSON en línea de comandos. Extrae, filtra y transforma JSON dentro de pipelines de shell sin un script de Python o Node — el camino más corto entre respuestas de API, archivos de logs o salida de kubectl y el campo que quieres.

¿Está jq disponible en Windows?

Sí. Instálalo con winget install jqlang.jq, Chocolatey choco install jq, o descarga el binario desde jqlang.org. Las reglas de comillas de PowerShell difieren de bash — si tienes dudas, guarda los filtros en un archivo .jq y ejecuta jq -f filter.jq.

¿En qué se diferencia jq de un formateador JSON de navegador?

Un JSON Formatter de navegador es interactivo — pegas JSON, ves resaltado y errores, copias el resultado. jq es no interactivo — describes la transformación una vez, corre en un pipeline de shell. Usa el navegador para depurar una respuesta única; usa jq para automatizar sobre cientos de entradas.

¿Por qué jq dice «Cannot iterate over null»?

Intentaste iterar (.[]) sobre un valor null — normalmente porque el campo no existía en la entrada. Arréglalo con el operador opcional .items[]? o da un valor por defecto con .items // [] | .[].

¿Puede jq modificar archivos en sitio?

No directamente — jq escribe a stdout. Usa un archivo temporal o sponge de moreutils: jq '.version = "2.0"' config.json | sponge config.json. Respalda siempre el original primero; un filtro mal escrito sobrescribirá el archivo.

¿Cómo uso jq con respuestas de curl?

Pipea curl -s a jq. El flag -s silencia la barra de progreso de curl para que solo el cuerpo JSON llegue a jq:

curl -s https://api.github.com/users/octocat | jq '.name, .blog'

¿Cuál es la diferencia entre el | de jq y el | del shell?

El pipe de shell pasa bytes entre procesos. El pipe jq pasa valores JSON entre filtros en una sola invocación de jq. Un comando con varios pipes internos corre en un proceso — más barato que encadenar jq | jq | jq.

¿Puede jq manejar JSON Lines (NDJSON)?

Sí, de forma nativa. jq lee cada línea como un valor JSON independiente cuando están separadas por espacios. Usa -c para emitir NDJSON y -s para recoger NDJSON en un único array.

¿Cómo formateo JSON sin filtrar?

Usa el filtro identidad: cat data.json | jq . o jq . < data.json. Parsea, valida y formatea con sangría de dos espacios — sin filtro alguno.

¿Existe una alternativa a jq con interfaz gráfica?

Sí. fx ofrece un TUI interactivo. Para una GUI sin instalación, el JSON Formatter basado en navegador cubre la mayoría de necesidades de exploración y validación. Herramientas web como jqplay.org ofrecen jq con previsualización en vivo.

¿Cuándo usar jq en vez de escribir un script Python?

Elige jq cuando la tarea sea puntual, quepa en un pipeline de shell y se mantenga dentro de la semántica de filtrar/transformar/extraer. Cambia a Python si necesitas pruebas unitarias, estado complejo, bibliotecas de terceros, o lógica que desborde la legibilidad de un archivo .jq.

¿Cómo uso expresiones regulares en jq?

jq expone regex mediante test("pattern"), match("pattern"), capture("pattern") y scan("pattern"), todos en sintaxis PCRE. Pasa flags como segundo argumento: test("abc"; "i") para ignorar mayúsculas/minúsculas. match devuelve offsets y capturas; scan emite cada coincidencia no superpuesta.

¿Cómo preservo los caracteres acentuados (ñ, á, é) en la salida de jq?

jq emite UTF-8 por defecto y conserva los acentos siempre que no uses -a / --ascii-output. Si ves \u00e1 en lugar de á, normalmente es el locale del terminal: verifica que $LANG sea es_ES.UTF-8 o en_US.UTF-8 y evita el flag -a.

Puntos clave

  1. Primero el modelo mental: entra un filtro, salen cero o más valores JSON, se componen con |. Todo lo demás es sintaxis.
  2. Aprende por tarea, no por operador: los 30 patrones cubren cerca del 95 % del uso diario de jq.
  3. Maneja null explícitamente: ? para saltar en silencio, // default para un respaldo concreto. La mayoría de arreglos de Cannot iterate over null pasan por uno de esos dos.
  4. Saber cuándo jq es la herramienta equivocada: las respuestas únicas pertenecen a un JSON Formatter de navegador; YAML pertenece a yq; la lógica compleja pertenece a código real.
  5. Combínalo con tu stack existente: jq brilla dentro de curl, kubectl, aws, docker y pipelines de logs. Úsalo como pegamento, no como capa de lógica.

Para flujos JSON relacionados, consulta la guía de formateo JSON5 y JSONC sobre extensiones de sintaxis para archivos de configuración, y la guía de conversión CSV a JSON para migraciones de formatos de datos donde jq encaja en el pipeline. Cuando tu JSON incluye timestamps, la guía del timestamp Unix cubre las trampas al transformar campos de fecha.

Artículos relacionados

Ver todos los artículos