Saltar al contenido principal

Clase 05 — jq Básico — El "sed" para JSON

jq es un procesador de JSON en línea de comandos. Es esencial para DevOps porque permite extraer, filtrar y transformar datos JSON desde la terminal.

Instalar jq

# macOS
brew install jq

# Ubuntu/Debian
sudo apt install jq

# CentOS/RHEL
sudo yum install jq

# Verificar
jq --version

Filtros básicos

# Identity (.) — Todo el JSON formateado
echo '{"a":1,"b":2}' | jq '.'

# Acceso a campos (.campo)
echo '{"nombre":"Ana","edad":28}' | jq '.nombre' # "Ana"
echo '{"nombre":"Ana"}' | jq -r '.nombre' # Ana (sin comillas)

# Campos anidados (.a.b.c)
echo '{"server":{"host":"db.com","port":5432}}' | jq '.server.host'

# Arrays (.[n])
echo '[10,20,30]' | jq '.[0]' # 10
echo '[10,20,30]' | jq '.[-1]' # 30
echo '[10,20,30]' | jq '.[1:3]' # [20, 30]

# Iterar arrays (.[]
echo '["a","b","c"]' | jq '.[]'
# "a"
# "b"
# "c"

Flags importantes de jq

# -r → Raw output (sin comillas)
echo '{"msg":"hola"}' | jq -r '.msg'

# -c → Compact (una línea)
echo '{"a":1,"b":2}' | jq -c '.'

# -e → Exit code basado en resultado (útil en scripts)
echo '{"ok":true}' | jq -e '.ok' > /dev/null && echo "Es true"

# -S → Ordenar claves
echo '{"z":1,"a":2,"m":3}' | jq -S '.'

# --arg → Pasar variables de bash a jq
nombre="Ana"
echo '{}' | jq --arg n "$nombre" '. + {nombre: $n}'

# --argjson → Pasar valores JSON (no strings)
echo '{}' | jq --argjson p 8080 '. + {puerto: $p}'

# -n → Sin input (crear JSON desde cero)
jq -n '{nombre: "Ana", edad: 28}'
jq -n --arg name "pikachu" --argjson hp 35 '{pokemon: $name, hp: $hp}'

Construir objetos

# Seleccionar campos específicos
echo '{"id":1,"nombre":"Ana","email":"ana@dev.com","temp":"x"}' | \
jq '{id, nombre, email}'

# Renombrar campos
echo '{"name":"Ana","age":28}' | jq '{nombre: .name, edad: .age}'

# Agregar campos calculados
echo '{"precio": 100}' | jq '. + {iva: (.precio * 0.21), total: (.precio * 1.21)}'

Pipe interno (|)

# Encadenar filtros
echo '{"usuarios":[{"nombre":"Ana","edad":28},{"nombre":"Carlos","edad":35}]}' | \
jq '.usuarios[] | .nombre'

# Filtrar y luego transformar
echo '{"datos":[1,2,3,4,5]}' | jq '.datos | map(. * 2)'
# [2, 4, 6, 8, 10]

Funciones útiles

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

# keys / values
echo '{"nombre":"Ana","edad":28}' | jq 'keys' # ["edad", "nombre"]
echo '{"nombre":"Ana","edad":28}' | jq 'values' # ["Ana", 28]

# has — Verificar si existe una clave
echo '{"nombre":"Ana"}' | jq 'has("nombre")' # true
echo '{"nombre":"Ana"}' | jq 'has("email")' # false

# type — Tipo del valor
echo '42' | jq 'type' # "number"

# if-then-else
echo '{"edad":20}' | jq 'if .edad >= 18 then "adulto" else "menor" end'

Ejemplo: Procesar output de AWS CLI

# Tabla de instancias EC2
jq -r '.Reservations[].Instances[] |
[
.InstanceId,
.InstanceType,
.State.Name,
(.Tags[] | select(.Key=="Name") | .Value)
] | @tsv' /tmp/ec2.json

# Solo instancias running
jq '[.Reservations[].Instances[] | select(.State.Name=="running")]' /tmp/ec2.json

# Contar por estado
jq '[.Reservations[].Instances[].State.Name] | group_by(.) | map({estado: .[0], total: length})' /tmp/ec2.json

Ejemplo: Procesar docker ps

# docker ps en formato JSON
docker ps --format '{{json .}}' | jq -s '.'

# Filtrar contenedores por imagen
docker ps --format '{{json .}}' | jq -s '[.[] | select(.Image | startswith("nginx"))]'

# Tabla formateada
docker ps --format '{{json .}}' | jq -r '[.Names, .Image, .Status] | @tsv'

Cheat Sheet de jq básico

ACCESO:          .campo | .a.b.c | .[0] | .[-1] | .[]
CONSTRUCCIÓN: {a, b} | {nuevo: .viejo} | . + {c: 3} | del(.campo)
FUNCIONES: length | keys | values | type | has("x") | to_entries | from_entries
FORMATEO: @tsv | @csv | @base64 | @uri
FLAGS: -r (raw) | -c (compacto) | -S (sort keys) | -e (exit code) | --arg k v | --argjson k v