Saltar al contenido principal

🐧 Linux Básico para DevOps: Bash, JSON, YAML y APIs

Clase práctica donde aprendemos los fundamentos de Linux, scripting en Bash, formatos de datos (JSON/YAML) y cómo consumir APIs desde la terminal. Todo lo que necesitás para empezar a automatizar.

🎬 Videos de la clase

▶️ Episodio #5 — De Bash a los Agentes IA

▶️ Episodio #6 — Jarvis despliega en AWS 🤖

▶️ Episodio #7 — curl y APIs: Tu primer superpoder DevOps en la terminal

Objetivos

  • Entender por qué Linux es esencial para DevOps
  • Dominar la terminal y los comandos básicos
  • Crear scripts de Bash con variables, condicionales y loops
  • Trabajar con JSON usando jq
  • Entender YAML y cuándo usarlo vs JSON
  • Consumir APIs REST con curl
  • Combinar curl + jq para procesar datos de APIs
  • Construir un proyecto integrador que combine todo

Prerequisitos

Haber completado el Módulo 01 o saber moverte en la terminal (cd, ls, pwd).

👉 Practicá en el Playground ROXS en KillerCoda

Estructura de tiempos (~3h)

BloqueTemaDuración
1Fundamentos de Linux y Terminal45 min
2Bash Core: Variables, I/O, Condicionales, Loops45 min
Break10 min
3JSON y YAML con jq40 min
4curl y APIs REST (PokéAPI)50 min
5Proyecto Integrador30 min

Bloque 1 — Fundamentos de Linux y Terminal

¿Por qué Linux en DevOps?

El 96% de los servidores del mundo corren Linux. No hay alternativa si querés hacer DevOps.

DóndeSistema
AWS, Azure, GCPLinux (Ubuntu, Amazon Linux, CentOS)
Docker containersLinux (Alpine, Debian)
KubernetesLinux
CI/CD (Jenkins, GitHub Actions)Linux
Servidores web (Nginx, Apache)Linux

¿Qué significa "saber Linux"?

No necesitás ser un gurú. Necesitás:

  1. Navegar por el sistema de archivos
  2. Editar archivos de configuración
  3. Ejecutar scripts y comandos
  4. Automatizar tareas repetitivas
  5. Diagnosticar problemas (logs, procesos, red)

La Terminal — Tu herramienta principal

La terminal es una interfaz basada en texto para comunicarte con el sistema operativo. En vez de hacer clic, escribís comandos.

┌─────────────────────────────────────────┐
│ Terminal / Consola / Shell │
│ │
│ $ whoami │
│ roxsross │
│ │
│ $ pwd │
│ /home/roxsross │
│ │
│ $ ls │
│ Desktop Documents Downloads │
└─────────────────────────────────────────┘

Terminal vs Shell

ConceptoQué es
TerminalLa ventana/aplicación donde escribís
ShellEl programa que interpreta tus comandos
BashUn tipo de shell (el más común en Linux)
ZshOtro shell (el default en macOS moderno)

El prompt

usuario@hostname:directorio$ _
# │ │ │ │
# │ │ │ └─ Aquí escribís
# │ │ └────────── En qué carpeta estás
# │ └─────────────────── Nombre de la máquina
# └─────────────────────────── Tu nombre de usuario

Comandos esenciales

# ¿Quién soy?
whoami

# ¿Dónde estoy?
pwd

# ¿Qué hay aquí?
ls
ls -la # Con detalles y archivos ocultos

# Moverse
cd carpeta/ # Entrar a una carpeta
cd .. # Subir un nivel
cd ~ # Ir al home
cd - # Volver al directorio anterior

# Crear
mkdir mi-carpeta # Crear carpeta
mkdir -p a/b/c # Crear carpetas anidadas
touch mi-archivo.txt # Crear archivo vacío

# Ver contenido
cat archivo.txt # Mostrar todo el archivo
head -5 archivo.txt # Primeras 5 líneas
tail -5 archivo.txt # Últimas 5 líneas

# Copiar, mover, borrar
cp archivo.txt copia.txt
mv archivo.txt nuevo-nombre.txt
rm archivo.txt
rm -r carpeta/ # Borrar carpeta (¡cuidado!)

# Buscar
find . -name "*.sh" # Buscar archivos .sh
grep "texto" archivo.txt # Buscar texto en un archivo

Tabla resumen de comandos

ComandoQué haceEjemplo
pwdMuestra dónde estáspwd
lsLista archivosls -la
cdCambia directoriocd /var/www
mkdirCrea carpetamkdir -p sitio
touchCrea archivo vacíotouch index.html
catMuestra contenidocat index.html
headPrimeras N líneashead -5 archivo
tailÚltimas N líneastail -5 archivo
cpCopiacp a.html b.html
mvMueve/renombramv a.html /tmp/
rmBorrarm archivo.txt
findBusca archivosfind . -name "*.sh"
grepBusca textogrep "error" log.txt
wcCuenta líneas/palabraswc -l archivo
sortOrdenasort archivo.txt
chmodCambia permisoschmod +x script.sh
whoamiMi usuariowhoami
hostnameMi hostnamehostname
dateFecha actualdate '+%Y-%m-%d'
unameInfo del sistemauname -a

Permisos en Linux

chmod +x script.sh     # Hacer ejecutable
chmod 755 carpeta/ # Permisos de carpeta
chmod 644 archivo.txt # Permisos de archivo
NúmeroSignificadoUso
755Dueño: todo. Otros: leer y ejecutarCarpetas y scripts
644Dueño: leer/escribir. Otros: solo leerArchivos normales
600Solo el dueño puede leer/escribirArchivos sensibles

El shebang

Todo script de Bash empieza con:

#!/bin/bash

Esta línea le dice al sistema: "Usá Bash para ejecutar este archivo". Siempre va en la primera línea.

Tu primer script

hola.sh
#!/bin/bash
# Mi primer script

echo "¡Hola Mundo!"
echo "Soy $(whoami) y estoy aprendiendo DevOps"
echo "Hoy es $(date '+%A %d de %B de %Y')"
# Crear, dar permisos y ejecutar
chmod +x hola.sh
./hola.sh

# Alternativa: sin chmod
bash hola.sh
Conceptos clave
  • #!/bin/bash (shebang): le dice al sistema que use Bash. Siempre va primero.
  • # son comentarios — Bash los ignora
  • echo imprime texto
  • $(comando) ejecuta un comando y usa su resultado (sustitución de comando)
Errores comunes
  • "Permission denied" → Falta chmod +x
  • "command not found" → Falta el ./ antes del nombre
  • "bad interpreter" → Error en la primera línea, verificar #!/bin/bash

Bloque 2 — Bash Core: Variables, I/O, Condicionales y Loops

📚 Para profundizar: Curso completo de Bash (6 clases)

Variables

#!/bin/bash
# CREAR: sin espacios alrededor del =
NOMBRE="DevOps"
NUMERO=42
CURSO="Bootcamp ROXS"

# USAR: con $
echo "Hola $NOMBRE"
echo "El número es $NUMERO"
echo "Curso: $CURSO"
Error #1 de novatos

NOMBRE = "valor" da error. Siempre sin espacios: NOMBRE="valor"

Variables del sistema

echo "Usuario: $USER"
echo "Home: $HOME"
echo "Shell: $SHELL"
echo "Path: $PATH"

Variables con comandos

# Guardar el resultado de un comando en una variable
FECHA=$(date '+%Y-%m-%d')
HORA=$(date '+%H:%M:%S')
USUARIO=$(whoami)
DIRECTORIO=$(pwd)
NUM_ARCHIVOS=$(ls | wc -l | tr -d ' ')

echo "Fecha: $FECHA"
echo "Hora: $HORA"
echo "Usuario: $USUARIO"
echo "Directorio: $DIRECTORIO"
echo "Archivos aquí: $NUM_ARCHIVOS"

Variables especiales

VariableDescripción
$0Nombre del script
$1, $2...Argumentos del script
$#Número de argumentos
$?Exit code del último comando
$HOMEDirectorio home
$USERUsuario actual
$SHELLShell actual

Aritmética

A=10
B=3
SUMA=$((A + B)) # 13
RESTA=$((A - B)) # 7
MULTI=$((A * B)) # 30
DIV=$((A / B)) # 3 (división entera)
MODULO=$((A % B)) # 1 (resto)

echo "$A + $B = $SUMA"
echo "$A * $B = $MULTI"

echo — Imprimir en pantalla

echo "Texto normal"
echo "Con variable: $NOMBRE"
echo "" # Línea vacía
echo -e "Con color: \033[32mVerde\033[0m" # Color verde
echo "$(date)" # Resultado de un comando

Entrada del usuario con read

#!/bin/bash

# Pedir un dato al usuario
echo "¿Cómo te llamás?"
read NOMBRE
echo "¡Hola, $NOMBRE!"

# Todo en una línea con -p (prompt)
read -p "¿Cuántos años tenés? " EDAD
echo "Tenés $EDAD años"

# Lectura silenciosa (para contraseñas)
read -s -p "Escribí tu contraseña: " PASSWORD
echo "" # Salto de línea porque -s no lo pone
echo "Contraseña recibida (${#PASSWORD} caracteres)"

Redirección — Enviar output a archivos

# > Crear archivo (o sobreescribir)
echo "Hola mundo" > salida.txt

# >> Agregar al final (append)
echo "Segunda línea" >> salida.txt

# Ver el contenido
cat salida.txt

# Guardar la salida de cualquier comando
date > fecha.txt
ls -la > lista-archivos.txt
whoami > usuario.txt

# Ocultar errores
comando 2>/dev/null

# Ocultar todo (stdout + stderr)
comando &>/dev/null

Pipes | — Encadenar comandos

El pipe | toma la salida de un comando y la pasa como entrada al siguiente.

# ¿Cuántos archivos .sh hay aquí?
ls *.sh | wc -l

# Buscar un proceso
ps aux | grep "node"

# Listar y ordenar por tamaño
ls -la | sort -k5 -n

# Encadenar varios pipes
cat /etc/passwd | grep "bash" | wc -l
┌──────────┐     ┌──────────┐     ┌──────────┐
│ Teclado │────>│ Programa │────>│ Pantalla │ (flujo normal)
│ (stdin) │ │ │ │ (stdout) │
└──────────┘ └──────────┘ └──────────┘

├──> archivo.txt (con > o >>)

└──> otro_programa (con |)

Condicionales — if / else

if [ condición ]; then
# Si es verdadero
echo "Sí"
elif [ otra_condición ]; then
echo "Otra cosa"
else
# Si es falso
echo "No"
fi
Espacios obligatorios

Los espacios dentro de [ ] son obligatorios. ["$VAR"="algo"] da error. Debe ser [ "$VAR" = "algo" ].

Comparar números

EDAD=25

if [ "$EDAD" -ge 18 ]; then
echo "✅ Mayor de edad"
else
echo "❌ Menor de edad"
fi
OperadorSignificado
-eqIgual
-neNo igual
-gtMayor que
-geMayor o igual
-ltMenor que
-leMenor o igual

Comparar strings (texto)

RESPUESTA="si"

if [ "$RESPUESTA" = "si" ]; then
echo "Dijiste sí"
elif [ "$RESPUESTA" = "no" ]; then
echo "Dijiste no"
else
echo "No entendí: $RESPUESTA"
fi
OperadorSignificado
"$A" = "$B"Strings iguales
"$A" != "$B"Strings diferentes
-z "$A"String vacío
-n "$A"String no vacío

Verificar archivos y directorios

ARCHIVO="config.json"

if [ -f "$ARCHIVO" ]; then
echo "El archivo $ARCHIVO existe"
cat "$ARCHIVO"
else
echo "El archivo $ARCHIVO no existe"
echo '{}' > "$ARCHIVO"
echo "Creado $ARCHIVO vacío"
fi
OperadorPregunta
-f archivo¿Existe el archivo?
-d carpeta¿Es un directorio?
-r archivo¿Puedo leerlo?
-w archivo¿Puedo escribirlo?
-x archivo¿Puedo ejecutarlo?

Verificar si un comando está instalado

for cmd in bash curl jq docker python3 kubectl; do
if command -v "$cmd" &>/dev/null; then
echo "✅ $cmd instalado → $(which "$cmd")"
else
echo "❌ $cmd NO instalado"
fi
done

Combinaciones lógicas (AND / OR)

EDAD=25
NOMBRE="roxs"

# AND: ambas condiciones deben ser verdad
if [ "$EDAD" -ge 18 ] && [ "$NOMBRE" = "roxs" ]; then
echo "Sos roxs y sos mayor de edad"
fi

# OR: al menos una condición debe ser verdad
if [ "$EDAD" -lt 13 ] || [ "$EDAD" -gt 65 ]; then
echo "Tarifa especial"
fi

Ejemplo práctico: saludo según la hora

HORA=$(date +%H)

if [ "$HORA" -ge 6 ] && [ "$HORA" -lt 12 ]; then
echo "🌅 Buenos días"
elif [ "$HORA" -ge 12 ] && [ "$HORA" -lt 18 ]; then
echo "☀️ Buenas tardes"
else
echo "🌙 Buenas noches"
fi

Bucles — Repetir acciones

for — Recorrer una lista

# Lista simple
for fruta in manzana banana naranja; do
echo "Me gusta la $fruta"
done

# Rango de números
for i in {1..5}; do
echo "Número: $i"
done

# Recorrer archivos
for archivo in *.sh; do
echo "Script encontrado: $archivo"
done

# Recorrer un array
POKEMONES=("Pikachu" "Charizard" "Mewtwo" "Gengar")
for pokemon in "${POKEMONES[@]}"; do
echo "⚡ $pokemon"
done

# Con índice
FRUTAS=("🍎 Manzana" "🍌 Banana" "🍊 Naranja")
for i in "${!FRUTAS[@]}"; do
echo "[$i] ${FRUTAS[$i]}"
done

while — Repetir mientras se cumpla una condición

# Contar del 1 al 5
CONTADOR=1
while [ "$CONTADOR" -le 5 ]; do
echo "Contando: $CONTADOR"
CONTADOR=$((CONTADOR + 1))
done

# Leer un archivo línea por línea
while IFS= read -r linea; do
echo "Línea: $linea"
done < archivo.txt

# Menú interactivo
while true; do
read -p "Escribí 'salir' para terminar: " OPCION
if [ "$OPCION" = "salir" ]; then
echo "¡Adiós!"
break
fi
echo "Escribiste: $OPCION"
done

for vs while

Usar for cuando...Usar while cuando...
Sabés la lista de antemanoNo sabés cuántas veces repetir
Recorrés archivosLeés líneas de un archivo
Iterás un rango fijoEsperás una condición

Errores comunes en Bash (y cómo evitarlos)

# Error 1: Espacios en variable
NOMBRE = "roxs" # ❌ bash: NOMBRE: command not found
NOMBRE="roxs" # ✅ Correcto

# Error 2: Sin espacios en [ ]
if ["$EDAD" -ge 18]; then # ❌ [25: command not found
if [ "$EDAD" -ge 18 ]; then # ✅ Correcto

# Error 3: Olvidar then
if [ "$EDAD" -ge 18 ] # ❌ syntax error
echo "Mayor"
fi

# Error 4: Olvidar fi
if [ "$EDAD" -ge 18 ]; then
echo "Mayor"
# ❌ unexpected end of file (falta fi)

# Error 5: Variable sin comillas en if
if [ $VAR = "algo" ]; then # ❌ Si VAR está vacía, da error
if [ "$VAR" = "algo" ]; then # ✅ Siempre usar comillas

Bloque 3 — JSON y YAML

📚 Para profundizar: Curso de JSON (10 clases) · Curso de YAML (10 clases)

JSON — JavaScript Object Notation

Es un formato de texto para representar datos estructurados. Es el formato más usado en APIs, configuraciones y comunicación entre servicios.

{
"nombre": "Pikachu",
"tipo": "electric",
"nivel": 42,
"activo": true
}

¿Dónde se usa JSON?

DóndeEjemplo
APIs RESTRespuestas de PokéAPI, GitHub API
Configuraciónpackage.json, .eslintrc.json
DockerInspeccionar contenedores
AWSPolíticas IAM, CloudFormation
TerraformState file

Tipos de datos en JSON

{
"string": "texto entre comillas",
"numero": 42,
"decimal": 3.14,
"booleano": true,
"nulo": null,
"array": [1, 2, 3],
"objeto": {
"clave": "valor"
}
}

Reglas de JSON

ReglaEjemplo
Las claves van entre comillas dobles"nombre": "pikachu"
Strings van entre comillas dobles"tipo": "electric"
Los números NO llevan comillas"hp": 35
Booleanos en minúscula"activo": true
Sin comas al final del último elemento{"a": 1, "b": 2}
Sin comentariosJSON no soporta // ni /* */

Objetos y Arrays

{
"equipo": [
{
"nombre": "Pikachu",
"tipo": ["electric"],
"hp": 35
},
{
"nombre": "Charizard",
"tipo": ["fire", "flying"],
"hp": 78
}
],
"entrenador": "Ash",
"region": "Kanto"
}

Errores comunes en JSON

❌ {'nombre': 'ash'}          → Comillas simples
✅ {"nombre": "ash"} → Comillas dobles

❌ {"a": 1, "b": 2,} → Coma al final
✅ {"a": 1, "b": 2}

❌ {nombre: "ash"} → Clave sin comillas
✅ {"nombre": "ash"}

jq — Tu cuchillo suizo para JSON

jq es una herramienta de línea de comandos para procesar JSON. Es esencial para DevOps.

# Instalar
# macOS: brew install jq
# Linux: sudo apt install jq

Uso básico

# Formatear JSON bonito
echo '{"nombre":"pikachu","hp":35}' | jq '.'

# Extraer un campo
echo '{"nombre":"pikachu","hp":35}' | jq '.nombre'
# "pikachu"

# Sin comillas (-r = raw)
echo '{"nombre":"pikachu","hp":35}' | jq -r '.nombre'
# pikachu

# Leer desde un archivo
jq '.' ejemplo.json
jq '.nombre' ejemplo.json
# Dado: {"entrenador": {"nombre": "Ash", "region": "Kanto"}}
echo '{"entrenador":{"nombre":"Ash","region":"Kanto"}}' | jq '.entrenador.nombre'
# "Ash"

Trabajar con arrays

JSON='{"movimientos":["thunderbolt","quick-attack","iron-tail"]}'

# Todos los elementos
echo "$JSON" | jq '.movimientos[]'

# Un elemento específico (índice desde 0)
echo "$JSON" | jq '.movimientos[0]'
# "thunderbolt"

# Último elemento
echo "$JSON" | jq '.movimientos[-1]'
# "iron-tail"

# Cantidad de elementos
echo "$JSON" | jq '.movimientos | length'
# 3

Crear nuevos objetos con jq

echo '{"name":"pikachu","weight":60,"height":4}' | jq '{
pokemon: .name,
peso_kg: (.weight / 10),
altura_m: (.height / 10)
}'
# {
# "pokemon": "pikachu",
# "peso_kg": 6,
# "altura_m": 0.4
# }

Construir JSON desde cero

jq -n \
--arg nombre "Gengar" \
--arg tipo "ghost" \
--argjson hp 60 \
--argjson ataque 65 \
'{pokemon: $nombre, tipo: $tipo, stats: {hp: $hp, ataque: $ataque}}'

Filtrar y ordenar

JSON='[
{"nombre": "Pikachu", "hp": 35},
{"nombre": "Charizard", "hp": 78},
{"nombre": "Mewtwo", "hp": 106}
]'

# Filtrar por HP > 50
echo "$JSON" | jq '.[] | select(.hp > 50) | .nombre'

# Ordenar por HP
echo "$JSON" | jq 'sort_by(.hp) | reverse'

# Promedio de HP
echo "$JSON" | jq '(map(.hp) | add) / length'

YAML — YAML Ain't Markup Language

Es otro formato para representar datos estructurados, pero más legible para humanos. No usa llaves ni comillas (en general).

nombre: Pikachu
tipo: electric
nivel: 42
activo: true

¿Dónde se usa YAML?

DóndeEjemplo
Docker Composedocker-compose.yml
KubernetesManifiestos (pods, deployments)
GitHub Actions.github/workflows/*.yml
AnsiblePlaybooks
CI/CD.gitlab-ci.yml, .travis.yml
AWS CloudFormationtemplate.yaml

En DevOps, YAML está en todas partes. Aprenderlo bien es fundamental.

Tipos de datos en YAML

# Strings (comillas opcionales)
nombre: Pikachu
nombre_con_comillas: "Pikachu"

# Números
hp: 35
peso: 6.0

# Booleanos
activo: true
legendario: false

# Null
dato_nulo: null
o_tambien: ~

# Comentarios (JSON no tiene esto!)
# Esto es un comentario

Listas (Arrays)

# Formato largo (recomendado)
movimientos:
- thunderbolt
- quick-attack
- iron-tail
- electro-ball

# Formato inline (como JSON)
movimientos: [thunderbolt, quick-attack, iron-tail]

Mapas (Objetos)

# Objeto anidado
entrenador:
nombre: Ash
edad: 10
region: Kanto

# Es equivalente al JSON:
# {"entrenador": {"nombre": "Ash", "edad": 10, "region": "Kanto"}}

Ejemplo completo: JSON vs YAML (lado a lado)

JSON:

{
"pokemon": "pikachu",
"tipo": ["electric"],
"nivel": 42,
"hp": 35,
"movimientos": [
"thunderbolt",
"quick-attack",
"iron-tail"
],
"entrenador": {
"nombre": "Ash",
"region": "Kanto"
}
}

YAML (mismo contenido):

pokemon: pikachu
tipo:
- electric
nivel: 42
hp: 35
movimientos:
- thunderbolt
- quick-attack
- iron-tail
entrenador:
nombre: Ash
region: Kanto
Regla de oro de YAML: ¡La indentación importa!
# ✅ Correcto (2 espacios)
entrenador:
nombre: Ash
region: Kanto

# ❌ Incorrecto (tabs)
entrenador:
nombre: Ash # ¡YAML no acepta tabs!

# ❌ Incorrecto (indentación inconsistente)
entrenador:
nombre: Ash
region: Kanto # Indentación diferente = error

YAML usa espacios, NUNCA tabs. Esto es la causa #1 de errores en YAML.

Ejemplo real: docker-compose.yml

version: "3.8"

services:
web:
image: nginx:alpine
ports:
- "80:80"
environment:
- NODE_ENV=production

api:
image: node:18-alpine
ports:
- "3000:3000"
depends_on:
- db

db:
image: postgres:15
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret123
POSTGRES_DB: myapp
volumes:
- db-data:/var/lib/postgresql/data

volumes:
db-data:

Comparativa: JSON vs YAML

CaracterísticaJSONYAML
Legibilidad🟡 Media🟢 Alta
VerbosidadMás caracteres ({}, "")Menos caracteres
Comentarios❌ No soporta✅ Con #
IndentaciónNo importa⚠️ Crucial
Soporte APIs✅ Estándar🟡 Raro
Soporte DevOps✅ Algo✅ Mucho
Parseo en Bash✅ Con jq🟡 Con yq

Regla práctica:

  • APIs y datos → JSON
  • Configuración y DevOps → YAML
  • ¿Podés elegir? → Usá lo que el proyecto ya usa

Bloque 4 — curl y APIs REST

📚 Para profundizar: Curso de curl (10 clases) · Curso de APIs (10 clases)

¿Qué es HTTP?

HTTP (HyperText Transfer Protocol) es el protocolo que usan los navegadores y aplicaciones para comunicarse con servidores.

┌──────────┐    Petición (Request)     ┌──────────┐
│ │ ──────────────────────────>│ │
│ Cliente │ GET /pokemon/pikachu │ Servidor │
│ (curl) │ │ (API) │
│ │<────────────────────────── │ │
└──────────┘ Respuesta (Response) └──────────┘
200 OK + JSON

Métodos HTTP

MétodoPara quéEjemplo
GETObtener datosConsultar un Pokémon
POSTCrear algo nuevoCrear un usuario
PUTActualizar (reemplazar)Cambiar perfil completo
PATCHActualizar (parcial)Cambiar solo el nombre
DELETEEliminarBorrar un registro

En esta clase usamos principalmente GET (leer datos).

Status Codes (Códigos de estado)

CódigoSignificadoCuándo lo ves
200OKTodo bien
201CreatedSe creó un recurso
301MovedRedirección permanente
400Bad RequestEnviaste algo mal
401UnauthorizedFalta autenticación
403ForbiddenNo tenés permiso
404Not FoundNo existe
429Too Many RequestsRate limit
500Server ErrorError del servidor

Regla fácil:

  • 2xx → Todo bien ✅
  • 3xx → Redirección ↩️
  • 4xx → Error tuyo ❌
  • 5xx → Error del servidor 💥

curl — Tu navegador en la terminal

curl (Client URL) es la herramienta estándar para hacer peticiones HTTP desde la terminal. Viene preinstalado en macOS y la mayoría de Linux.

GET básico

# Petición GET simple
curl https://pokeapi.co/api/v2/pokemon/pikachu

# Con formato bonito (usando jq)
curl -s https://pokeapi.co/api/v2/pokemon/pikachu | jq '.'

Flags importantes

# -s (silent) — Sin barra de progreso
curl -s https://pokeapi.co/api/v2/pokemon/pikachu

# -v (verbose) — Ver headers y detalles
curl -v https://pokeapi.co/api/v2/pokemon/pikachu

# -o (output) — Guardar en archivo
curl -s https://pokeapi.co/api/v2/pokemon/pikachu -o pikachu.json

# -w (write-out) — Mostrar info extra
curl -s -o /dev/null -w "HTTP %{http_code}\n" https://pokeapi.co/api/v2/pokemon/pikachu
# HTTP 200

# -I (HEAD) — Solo ver headers
curl -I https://pokeapi.co/api/v2/pokemon/pikachu

# -L (follow redirects) — Seguir redirecciones
curl -sL https://httpbin.org/redirect/1

# Combinar flags
curl -s -o /dev/null -w "%{http_code}" https://google.com
# 200

Tabla resumen de flags

FlagNombrePara qué
-sSilentSin barra de progreso
-SShow errorMostrar errores (con -s)
-vVerboseVer todo el detalle
-o fileOutputGuardar en archivo
-ORemote nameGuardar con nombre original
-w formatWrite-outMostrar métricas (status code, tiempo)
-IHeadSolo headers
-LLocationSeguir redirecciones
-H "k: v"HeaderAgregar un header
-d "data"DataEnviar datos (POST)
-X METHODRequestEspecificar método HTTP
--max-time NTimeoutTimeout en segundos

APIs REST — ¿Qué son?

Una API (Application Programming Interface) es una forma de que dos programas se comuniquen entre sí. Una API REST usa HTTP y generalmente devuelve JSON.

Tu terminal (curl) ──HTTP GET──> Servidor (PokéAPI) ──JSON──> Tu terminal

URLs de una API REST

https://pokeapi.co/api/v2/pokemon/pikachu
│ │ │ │ │
│ │ │ │ └─ Recurso específico
│ │ │ └─────── Colección
│ │ └──────────── Versión de la API
│ └────────────────────────── Dominio
└────────────────────────────────── Protocolo

Ejemplo con PokéAPI

# Listar los primeros 5 Pokémon
curl -s https://pokeapi.co/api/v2/pokemon?limit=5 | jq '.results[].name'

# Obtener un Pokémon específico
curl -s https://pokeapi.co/api/v2/pokemon/25 | jq '.name'
# "pikachu"

# Obtener un tipo
curl -s https://pokeapi.co/api/v2/type/electric | jq '.pokemon[:3][].pokemon.name'

curl + jq — La combinación poderosa

Extraer datos específicos

# Nombre y peso de Pikachu
curl -s https://pokeapi.co/api/v2/pokemon/pikachu | jq '{
nombre: .name,
peso_kg: (.weight / 10),
altura_m: (.height / 10)
}'

# Solo los tipos
curl -s https://pokeapi.co/api/v2/pokemon/charizard | jq '[.types[].type.name]'
# ["fire", "flying"]

# HP (primer stat)
curl -s https://pokeapi.co/api/v2/pokemon/mewtwo | jq '.stats[0].base_stat'
# 106

# Datos completos formateados
curl -s https://pokeapi.co/api/v2/pokemon/pikachu | jq '{
nombre: .name,
id: .id,
tipos: [.types[].type.name],
peso_kg: (.weight / 10),
altura_m: (.height / 10),
hp: .stats[0].base_stat,
ataque: .stats[1].base_stat,
defensa: .stats[2].base_stat
}'

Guardar respuesta en variable

# Guardar y reutilizar (una sola petición, múltiples extracciones)
RESPUESTA=$(curl -s https://pokeapi.co/api/v2/pokemon/pikachu)

NOMBRE=$(echo "$RESPUESTA" | jq -r '.name')
TIPOS=$(echo "$RESPUESTA" | jq -r '[.types[].type.name] | join(", ")')
HP=$(echo "$RESPUESTA" | jq '.stats[0].base_stat')
PESO=$(echo "$RESPUESTA" | jq '(.weight / 10)')

echo "Pokémon: $NOMBRE"
echo "Tipos: $TIPOS"
echo "HP: $HP"
echo "Peso: ${PESO}kg"

Loop: buscar varios Pokémon

echo "=== Mi Pokédex ==="
for pokemon in pikachu charizard mewtwo bulbasaur gengar; do
info=$(curl -s "https://pokeapi.co/api/v2/pokemon/$pokemon")
nombre=$(echo "$info" | jq -r '.name')
tipos=$(echo "$info" | jq -r '[.types[].type.name] | join(", ")')
hp=$(echo "$info" | jq '.stats[0].base_stat')
echo " $nombre | Tipo: $tipos | HP: $hp"
done

Tabla formateada

API="https://pokeapi.co/api/v2/pokemon"

echo " ┌──────────────┬───────────────────┬──────┐"
echo " │ Pokémon │ Tipo(s) │ HP │"
echo " ├──────────────┼───────────────────┼──────┤"

for pokemon in pikachu charizard mewtwo bulbasaur gengar; do
info=$(curl -s "$API/$pokemon")
nombre=$(echo "$info" | jq -r '.name')
tipos=$(echo "$info" | jq -r '[.types[].type.name] | join(", ")')
hp=$(echo "$info" | jq '.stats[0].base_stat')
printf " │ %-12s │ %-17s │ %4s │\n" "$nombre" "$tipos" "$hp"
done

echo " └──────────────┴───────────────────┴──────┘"

Verificar si la petición fue exitosa

POKEMON="pikachu"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://pokeapi.co/api/v2/pokemon/$POKEMON")

if [ "$HTTP_CODE" = "200" ]; then
echo "✅ Pokémon encontrado"
curl -s "https://pokeapi.co/api/v2/pokemon/$POKEMON" | jq '.name'
elif [ "$HTTP_CODE" = "404" ]; then
echo "❌ Pokémon '$POKEMON' no existe"
else
echo "⚠️ Error HTTP: $HTTP_CODE"
fi

Medir tiempo de respuesta

for url in "https://google.com" "https://pokeapi.co/api/v2/pokemon/pikachu" "https://httpbin.org/delay/1"; do
echo -n "⏱️ $url → "
curl -s -o /dev/null -w "%{time_total}s (HTTP %{http_code})\n" -L "$url"
done

Generar JSON de un equipo completo

API="https://pokeapi.co/api/v2/pokemon"
EQUIPO_JSON="["
FIRST=true

for pokemon in pikachu charizard mewtwo; do
info=$(curl -s "$API/$pokemon")
pokemon_json=$(echo "$info" | jq '{nombre: .name, tipos: [.types[].type.name], hp: .stats[0].base_stat}')
if [ "$FIRST" = true ]; then
EQUIPO_JSON="$EQUIPO_JSON$pokemon_json"
FIRST=false
else
EQUIPO_JSON="$EQUIPO_JSON,$pokemon_json"
fi
done

EQUIPO_JSON="$EQUIPO_JSON]"
echo "$EQUIPO_JSON" | jq '.'

Bloque 5 — Proyecto Integrador

Poner en práctica todo lo aprendido en un solo proyecto guiado. Usamos:

  • ✅ Variables Bash
  • ✅ Condicionales y loops
  • ✅ JSON y jq
  • ✅ curl + APIs
  • ✅ Redirección a archivos

Proyecto: System Info Reporter

Un script que recopila información del sistema y genera un reporte en JSON.

┌─────────────────────────────────────────────┐
│ System Info Reporter │
│ │
│ 1. Lee info del sistema (OS, CPU, RAM) │
│ 2. Obtiene IP pública con curl │
│ 3. Genera un JSON con todo │
│ 4. Muestra un resumen en la terminal │
│ 5. Guarda el reporte en un archivo │
└─────────────────────────────────────────────┘
system-info.sh
#!/bin/bash
set -euo pipefail

echo "╔══════════════════════════════════════╗"
echo "║ System Info Reporter ║"
echo "╚══════════════════════════════════════╝"

# Variables del sistema
OS=$(uname -s)
HOSTNAME_VAR=$(hostname)
USUARIO=$(whoami)
FECHA=$(date '+%Y-%m-%d %H:%M:%S')

# IP pública con curl
IP_PUBLICA=$(curl -s --max-time 5 https://ifconfig.me 2>/dev/null || echo "N/A")

# Mostrar en pantalla
echo ""
echo "📋 Info del sistema:"
echo " OS: $OS"
echo " Hostname: $HOSTNAME_VAR"
echo " Usuario: $USUARIO"
echo " Fecha: $FECHA"
echo " IP: $IP_PUBLICA"

# Generar JSON con jq
REPORTE=$(jq -n \
--arg os "$OS" \
--arg host "$HOSTNAME_VAR" \
--arg user "$USUARIO" \
--arg fecha "$FECHA" \
--arg ip "$IP_PUBLICA" \
'{
sistema: {os: $os, hostname: $host},
usuario: $user,
fecha: $fecha,
ip_publica: $ip
}')

# Guardar en archivo
ARCHIVO="/tmp/system-report-$(date +%Y%m%d-%H%M%S).json"
echo "$REPORTE" > "$ARCHIVO"

echo ""
echo "📄 JSON generado:"
echo "$REPORTE" | jq '.'
echo ""
echo "✅ Reporte guardado en $ARCHIVO"

Mini Pokédex CLI

pokedex.sh
#!/bin/bash
API="https://pokeapi.co/api/v2/pokemon"

echo "╔══════════════════════════════════════╗"
echo "║ 🔴 Pokédex CLI ║"
echo "╚══════════════════════════════════════╝"
echo ""

read -p "🔍 Buscá un Pokémon: " POKEMON
POKEMON=$(echo "$POKEMON" | tr '[:upper:]' '[:lower:]')

HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$API/$POKEMON")

if [ "$HTTP_CODE" = "200" ]; then
RESPUESTA=$(curl -s "$API/$POKEMON")
echo ""
echo "$RESPUESTA" | jq '{
nombre: .name,
id: .id,
tipos: [.types[].type.name],
peso_kg: (.weight / 10),
altura_m: (.height / 10),
hp: .stats[0].base_stat,
ataque: .stats[1].base_stat,
defensa: .stats[2].base_stat
}'
else
echo "❌ Pokémon '$POKEMON' no encontrado (HTTP $HTTP_CODE)"
fi

Proyecto Mini: Todo junto

proyecto-mini.sh
#!/bin/bash
API="https://pokeapi.co/api/v2/pokemon"

echo "=== 🎮 Mi Pokédex Personal ==="
echo ""

# 1. Pedir datos al usuario
read -p "¿Cómo te llamás? " NOMBRE
read -p "¿Cuál es tu Pokémon favorito? " MI_POKEMON
MI_POKEMON=$(echo "$MI_POKEMON" | tr '[:upper:]' '[:lower:]')

echo ""
echo "🔍 Buscando a $MI_POKEMON..."

# 2. Buscar en la API
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$API/$MI_POKEMON")

if [ "$HTTP_CODE" != "200" ]; then
echo "❌ No se encontró '$MI_POKEMON'"
exit 1
fi

DATOS=$(curl -s "$API/$MI_POKEMON")

# 3. Extraer datos con jq
POKE_NOMBRE=$(echo "$DATOS" | jq -r '.name')
POKE_TIPO=$(echo "$DATOS" | jq -r '[.types[].type.name] | join(", ")')
POKE_HP=$(echo "$DATOS" | jq '.stats[0].base_stat')

# 4. Mostrar
echo ""
echo "📋 Datos de tu Pokémon:"
echo " Nombre: $POKE_NOMBRE"
echo " Tipo: $POKE_TIPO"
echo " HP: $POKE_HP"

# 5. Guardar en JSON
OUTPUT="/tmp/mi-pokedex.json"
cat > "$OUTPUT" << EOF
{
"entrenador": "$NOMBRE",
"fecha": "$(date '+%Y-%m-%d')",
"pokemon_favorito": {
"nombre": "$POKE_NOMBRE",
"tipo": "$POKE_TIPO",
"hp": $POKE_HP
}
}
EOF

echo ""
echo "📄 Guardado en $OUTPUT"
jq '.' "$OUTPUT"

Resumen: ¿Qué aprendimos hoy?

ConceptoLo que vimos
Terminalpwd, ls, cd, cat, chmod, find, grep
BashVariables, echo, read, if/else, for, while
I/ORedirección (>, >>), pipes (|)
JSONObjetos, arrays, tipos de datos, reglas
jq.campo, .array[], -r, length, select, sort_by
YAMLListas, mapas, indentación, comentarios
curl-s, -v, -o, -w, -I, -L, guardar respuestas
APIsREST, GET, POST, status codes, PokéAPI
Pipescurl -s URL | jq '.campo'

🏠 Tarea para casa

  1. Completar todos los ejercicios de esta clase
  2. Ejecutar el System Info Reporter y agregar al menos una sección nueva
  3. Crear tu propio script que busque un Pokémon en la PokéAPI y guarde el resultado en JSON
  4. Explorar los ejemplos prácticos
  5. Practicar en el Playground ROXS

📚 Recursos del Bootcamp — Profundizá cada tema

Cada tema de esta clase tiene un curso completo con clases individuales, ejemplos y ejercicios:

RecursoClasesDescripción
🐚 Bash6 clasesVariables, I/O, condicionales, loops, funciones
📘 JSON10 clasesTipos, objetos, arrays, jq básico y avanzado, APIs, DevOps
📘 YAML10 clasesTipos, listas, mapas, anclas, Docker Compose, Kubernetes, CI/CD
🌐 curl10 clasesMétodos HTTP, headers, auth, envío de datos, debug, scripting
🔌 APIs10 clasesHTTP, REST, autenticación, consumir y diseñar APIs, testing
📝 Markdown6 clasesFormato, listas, código, tablas, GitHub Flavored, DevOps
🧪 Proyectos6 proyectosSystem Info, Pokédex CLI, API Monitor, Config Manager, Deploy Script, Log Analyzer
🎯 ¿Cómo usar estos recursos?

Seguí el orden: Bash → JSON → YAML → curl → APIs. Cada recurso tiene clases progresivas con teoría, ejemplos y ejercicios prácticos.


🔗 Recursos externos