¿Odias los anuncios? Ir Sin publicidad Hoy

jq One-Liners Filtrar y transformar JSON desde la línea de comandos sin escribir un script

Actualizado en

Siete recetas prácticas de jq para desarrolladores backend y DevOps — que abarcan select, map, to_entries, del, group_by y la reestructuración de APIs en entornos reales. Se muestra la entrada y la salida para cada patrón.

jq One-Liners: Filtrar y transformar JSON desde la línea de comandos sin escribir un script 1
ANUNCIO · ¿ELIMINAR?

Estás viendo una respuesta de API minificada en tu terminal. Necesitas extraer 3 campos, filtrar los nulos y pipear el resultado a algo más. Escribir un script en Python para esto sería 20 líneas y 2 minutos que no tienes. jq Lo maneja en una sola orden — si conoces los patrones.

Siete recetas a continuación. Cada una cubre un patrón que verás repetidamente al trabajar con respuestas de API o archivos de registro. Se muestra la entrada, el comando y la salida para cada receta.

Instalar

brew install jq        # macOS
apt-get install jq     # Ubuntu/Debian
apk add jq             # Alpine (Docker images)

Receta 1: Extraer un campo de cada objeto en un array

La cosa más común que harás con jq: extraer un campo de cada elemento en un array de JSON.

Entrada (users.json)

[
  {"id": 1, "name": "Alice", "email": "alice@example.com", "role": "admin"},
  {"id": 2, "name": "Bob",   "email": "bob@example.com",   "role": "user"},
  {"id": 3, "name": "Carol", "email": "carol@example.com", "role": "user"}
]
jq '.[].name' users.json
# → "Alice"
#   "Bob"
#   "Carol"  (newline-separated stream)

.[] itera sobre cada elemento del array; .name extrae el campo. La salida es un flujo — útil para pipear a otros comandos. Si necesitas un array de JSON completo:

jq 'map(.name)' users.json
# → ["Alice", "Bob", "Carol"]

map(.name) es abreviatura de [.[] | .name] — aplica la expresión a cada elemento y envuelve los resultados en un array. Lo usarás mucho. map() mucho.

Receta 2: Filtrar con select

Mantén solo los objetos que cumplen con una condición; descarta el resto.

jq 'map(select(.role == "admin"))' users.json
[
  {"id": 1, "name": "Alice", "email": "alice@example.com", "role": "admin"}
]

select(expr) envía el elemento solo cuando la expresión es verdadera — todo lo demás desaparece. Envolverlo en map() mantiene la salida como un array. Más ejemplos:

# Numeric comparison
jq 'map(select(.score > 80))' results.json

# Not-null check
jq 'map(select(.error != null))' events.json

# String contains (requires test)
jq 'map(select(.message | test("timeout")))' logs.json

Receta 3: Rediseñar objetos con map

Selecciona solo los campos que necesitas y opcionalmente renombra en la misma pasada.

jq 'map({name: .name, role: .role})' users.json
[
  {"name": "Alice", "role": "admin"},
  {"name": "Bob",   "role": "user"},
  {"name": "Carol", "role": "user"}
]

Estás construyendo un nuevo objeto literal para cada elemento. Para renombrar una clave, cambia el lado izquierdo de la coma:

jq 'map({username: .name, access_level: .role})' users.json

Una abreviatura que ahorra teclas: {name} es equivalente a {name: .name}. Si quieres un campo tal como está, no necesitas escribir la clave dos veces:

jq 'map({id, name, role})' users.json

Receta 4: Renombrar claves con to_entries y from_entries

map es útil cuando sabes cuáles claves existen. Cuando necesitas transformar las claves mismas — añadir un prefijo, convertir convenciones de nomenclatura o renombrar según una búsqueda — to_entries es el patrón adecuado.

Entrada (config.json)

{"api_url": "https://api.example.com", "timeout": 30, "retry_count": 3}
# Add cfg_ prefix to every key
jq 'to_entries | map(.key = "cfg_" + .key) | from_entries' config.json
{"cfg_api_url": "https://api.example.com", "cfg_timeout": 30, "cfg_retry_count": 3}

to_entries convierte {"k": "v"} en [{"key": "k", "value": "v"}]. Después de modificar los elementos en el array resultante, from_entries reconstruye el objeto. Para renombrar una clave específica sin tocar las demás:

jq 'to_entries | map(if .key == "api_url" then .key = "endpoint" else . end) | from_entries' config.json

Receta 5: Eliminar campos con del

La inversa de rediseñar: mantener todo y eliminar algunos campos específicos. El caso principal es eliminar datos sensibles antes de registrarlos o antes de pasar un payload a un servicio de terceros.

jq 'map(del(.email))' users.json
[
  {"id": 1, "name": "Alice", "role": "admin"},
  {"id": 2, "name": "Bob",   "role": "user"},
  {"id": 3, "name": "Carol", "role": "user"}
]

Eliminar múltiples campos de forma simultánea, o eliminar rutas anidadas:

# Multiple top-level fields at once
jq 'del(.password, .token, .refresh_token)' user.json

# Nested path
jq 'del(.user.internal_id)' response.json

# All fields named "debug" at any depth (recursive descent)
jq 'del(.. | .debug? // empty)' response.json

Receta 6: Filtrar, rediseñar y ordenar en una sola pasada

La verdadera recompensa es encadenar estos elementos básicos. Aquí hay un patrón que aparece constantemente al trabajar con respuestas paginadas de API: descender en un array anidado, filtrarlo, rediseñar los objetos y ordenar el resultado.

Entrada (repos.json)

{
  "total_count": 3,
  "items": [
    {"id": 1, "name": "repo-alpha", "stargazers_count": 142, "language": "Go",     "private": false},
    {"id": 2, "name": "repo-beta",  "stargazers_count": 89,  "language": "Python", "private": true},
    {"id": 3, "name": "repo-gamma", "stargazers_count": 310, "language": "Go",     "private": false}
  ]
}
jq '.items
  | map(select(.private == false and .language == "Go"))
  | sort_by(-.stargazers_count)
  | map({name, stars: .stargazers_count})' repos.json
[
  {"name": "repo-gamma", "stars": 310},
  {"name": "repo-alpha", "stars": 142}
]

El pipeline:

  • .items — descender en el array anidado
  • map(select(...)) — filtrar en una sola pasada; and encadena condiciones
  • sort_by(-.stargazers_count) — negar el valor para orden descendente; sort_by(.field) solamente da orden ascendente
  • map({name, stars: .stargazers_count}) — rediseño final; {name} es abreviatura de {name: .name}

Receta 7: Contar niveles de registro con group_by

Análisis de frecuencia en salida estructurada de registros — sin necesidad de base de datos, sin ejercicios de awk.

Entrada (logs.json)

[
  {"level": "error", "msg": "connection timeout",     "service": "auth"},
  {"level": "info",  "msg": "request received",       "service": "api"},
  {"level": "error", "msg": "null pointer exception", "service": "worker"},
  {"level": "warn",  "msg": "slow query detected",    "service": "db"},
  {"level": "error", "msg": "rate limit exceeded",    "service": "api"}
]
jq 'group_by(.level) | map({level: .[0].level, count: length}) | sort_by(-.count)' logs.json
[
  {"level": "error", "count": 3},
  {"level": "info",  "count": 1},
  {"level": "warn",  "count": 1}
]

group_by(.level) devuelve un array de arrays — cada sub-array contiene todos los elementos que comparten el mismo valor de nivel. .[0].level extrae el nombre del nivel del primer elemento del grupo; length cuenta cuántos elementos hay en el grupo.

Añadir un desglose por servicio en la misma consulta:

jq 'group_by(.level) | map({
  level:    .[0].level,
  count:    length,
  services: map(.service) | unique
})' logs.json

Guía rápida

Los patrones anteriores en forma de tabla para cuando necesitas un recordatorio rápido:

Lo que deseasExpresión de jq
Todos los valores de un campomap(.field)
Filtrar elementos coincidentesmap(select(.field == "val"))
Rediseñar cada objetomap({newKey: .oldKey})
Renombrar todas las clavesto_entries | map(.key = ...) | from_entries
Eliminar camposmap(del(.field1, .field2))
Ordenar ascendentementesort_by(.field)
Ordenar descendentesort_by(-.field)
Contar por grupogroup_by(.field) | map({key: .[0].field, count: length})
Obtener todas las claves de un objetokeys
Contar elementos en un arraylength
Valores únicos de un campomap(.field) | unique

Antes de comenzar: Dominar el bloque

Las respuestas de API a menudo llegan minificadas o profundamente anidadas. Si no estás seguro del camino que necesitas, pega el JSON en el Formateador JSON — lo imprime de forma legible con nodos colapsables para que puedas identificar el camino antes de escribir la jq expresión. Después de aplicar una transformación, la Comparar JSON herramienta es útil para verificar la diferencia antes y después cuando estás rediseñando o eliminando campos y deseas confirmar que nada cambió inesperadamente.

Estos siete patrones cubren la mayor parte de las tareas de manipulación de JSON que harás en la línea de comandos. El verdadero poder está en encadenarlos — una vez que puedas filtrar, rediseñar y ordenar, podrás procesar la mayoría de las respuestas de API sin tocar un archivo de script.

También te puede interesar

¿Quieres eliminar publicidad? Adiós publicidad hoy

Instalar extensiones

Agregue herramientas IO a su navegador favorito para obtener acceso instantáneo y búsquedas más rápidas

añadir Extensión de Chrome añadir Extensión de borde añadir Extensión de Firefox añadir Extensión de Opera

¡El marcador ha llegado!

Marcador es una forma divertida de llevar un registro de tus juegos, todos los datos se almacenan en tu navegador. ¡Próximamente habrá más funciones!

ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?

Noticias Aspectos técnicos clave

Involucrarse

Ayúdanos a seguir brindando valiosas herramientas gratuitas

Invítame a un café
ANUNCIO · ¿ELIMINAR?