Saltar al contenido principal

🏋️ Ejercicios — Clase 02: Linux Básico para DevOps

Practicá todo lo que viste en la Clase 02. Cada ejercicio tiene pistas y solución. Intentá resolverlo solo antes de mirar.

👉 Usá el Playground ROXS en KillerCoda para practicar.


Ejercicio 1 — Bash Básico: Variables y sistema

Nivel: 🟢 Fácil

Creá un script mi-info.sh que:

  1. Cree una variable MI_NOMBRE con tu nombre
  2. Cree una variable MI_EDAD con tu edad
  3. Muestre "Hola, soy [nombre] y tengo [edad] años"
  4. Guarde en una variable FECHA_HOY el resultado del comando date
  5. Guarde en ARCHIVOS_AQUI cuántos archivos hay en el directorio actual
  6. Muestre "Hoy es: [fecha]" y "Archivos aquí: [número]"
  7. Use un if para verificar si MI_EDAD es mayor o igual a 18
  8. Use un for para mostrar los números del 1 al 5

Ejemplo de salida:

Hola, soy RoxsRoss y tengo 25 años

Hoy es: sáb feb 21 15:30:00 -03 2026
Archivos aquí: 12

Eres mayor de edad

Número: 1
Número: 2
Número: 3
Número: 4
Número: 5
💡 Pistas
  • MI_NOMBRE="Juan" — sin espacios alrededor del =
  • FECHA_HOY=$(date) — guardar resultado de comando
  • ARCHIVOS_AQUI=$(ls | wc -l | tr -d ' ') — contar archivos
  • if [ "$MI_EDAD" -ge 18 ]; then ... fi
  • for i in 1 2 3 4 5; do ... done
✅ Solución
#!/bin/bash
# Ejercicio 01: Bash Básico

# Parte 1: Variables
MI_NOMBRE="RoxsRoss"
MI_EDAD=25

echo "Hola, soy $MI_NOMBRE y tengo $MI_EDAD años"
echo ""

# Parte 2: Comandos del sistema
FECHA_HOY=$(date)
ARCHIVOS_AQUI=$(ls | wc -l | tr -d ' ')

echo "Hoy es: $FECHA_HOY"
echo "Archivos aquí: $ARCHIVOS_AQUI"
echo ""

# Parte 3: Condicional
if [ "$MI_EDAD" -ge 18 ]; then
echo "Eres mayor de edad"
else
echo "Eres menor de edad"
fi
echo ""

# Parte 4: Loop
for i in 1 2 3 4 5; do
echo "Número: $i"
done

Ejercicio 2 — Variables avanzadas y aritmética

Nivel: 🟢 Fácil

Creá un script calculadora.sh que:

  1. Pida dos números al usuario con read
  2. Muestre el resultado de: suma, resta, multiplicación y división
  3. Muestre también las variables del sistema: $USER, $HOME, $SHELL
  4. Guarde la fecha en formato YYYY-MM-DD en una variable

Ejemplo de salida:

🔢 Calculadora Bash
Ingresá el primer número: 15
Ingresá el segundo número: 4
━━━━━━━━━━━━━━━━━━━━
15 + 4 = 19
15 - 4 = 11
15 * 4 = 60
15 / 4 = 3
━━━━━━━━━━━━━━━━━━━━
Usuario: root
Home: /root
Shell: /bin/bash
Fecha: 2026-02-21
💡 Pistas
  • read -p "Texto: " VARIABLE para pedir input
  • Bash solo hace matemática entera: $((A + B))
  • date '+%Y-%m-%d' para formato de fecha
✅ Solución
#!/bin/bash
echo "🔢 Calculadora Bash"
read -p "Ingresá el primer número: " A
read -p "Ingresá el segundo número: " B

echo "━━━━━━━━━━━━━━━━━━━━"
echo " $A + $B = $((A + B))"
echo " $A - $B = $((A - B))"
echo " $A * $B = $((A * B))"

if [ "$B" -ne 0 ]; then
echo " $A / $B = $((A / B))"
else
echo " $A / $B = Error: división por cero"
fi

echo "━━━━━━━━━━━━━━━━━━━━"
echo "Usuario: $USER"
echo "Home: $HOME"
echo "Shell: $SHELL"
echo "Fecha: $(date '+%Y-%m-%d')"

Ejercicio 3 — Condicionales y verificaciones

Nivel: 🟢 Fácil

Creá verificar-sistema.sh que:

  1. Verifique si sos root ($USER o $EUID)
  2. Verifique si existen los archivos /etc/hosts y /etc/passwd
  3. Verifique si los comandos curl, jq, git y docker están instalados
  4. Muestre un saludo según la hora del día (mañana/tarde/noche)
  5. Muestre cada check con ✅ o ❌
💡 Pistas
  • [ "$USER" = "root" ] para verificar root
  • [ -f "/etc/hosts" ] para verificar archivo
  • command -v curl &>/dev/null para verificar comando
  • HORA=$(date +%H) para obtener la hora
✅ Solución
#!/bin/bash
echo "🔍 Verificación del sistema"
echo ""

# Check 1: root
if [ "$USER" = "root" ]; then
echo "✅ Sos root"
else
echo "❌ No sos root (sos $USER)"
fi

# Check 2: archivos
for archivo in /etc/hosts /etc/passwd /etc/shadow; do
if [ -f "$archivo" ]; then
echo "✅ $archivo existe"
else
echo "❌ $archivo NO existe"
fi
done

# Check 3: comandos
for cmd in curl jq git docker; do
if command -v "$cmd" &>/dev/null; then
echo "✅ $cmd instalado"
else
echo "❌ $cmd NO instalado"
fi
done

# Check 4: saludo
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

Ejercicio 4 — JSON con jq

Nivel: 🟡 Intermedio

Creá un archivo mi-pokemon.json con tu Pokémon favorito que tenga: nombre, tipo (array), nivel, hp y 3 movimientos. Luego:

  1. Crear el JSON a mano (válido)
  2. Verificar que es válido con jq '.'
  3. Extraer solo el nombre
  4. Extraer todos los movimientos
  5. Contar cuántos movimientos tiene
  6. Extraer el primer movimiento
  7. Crear un nuevo JSON con solo nombre y hp

Bonus: Creá un JSON con un equipo de 3 Pokémon (array de objetos) y usá jq para:

  • Mostrar solo los nombres
  • Mostrar el Pokémon con mayor nivel (sort_by)
💡 Pistas
  • jq '.nombre' archivo.json para extraer un campo
  • jq -r '.nombre' para sin comillas
  • jq '.movimientos[]' para todos los elementos del array
  • jq '.movimientos | length' para contar
  • jq '{nombre: .nombre, hp: .hp}' para crear nuevo objeto
  • jq '.equipo | sort_by(.nivel) | last' para el de mayor nivel
✅ Solución
mi-pokemon.json
{
"nombre": "Charizard",
"tipo": ["fire", "flying"],
"nivel": 50,
"hp": 78,
"movimientos": ["flamethrower", "fly", "dragon-claw"]
}
# Verificar
jq '.' mi-pokemon.json

# Extraer nombre
jq -r '.nombre' mi-pokemon.json

# Todos los movimientos
jq '.movimientos[]' mi-pokemon.json

# Contar movimientos
jq '.movimientos | length' mi-pokemon.json

# Primer movimiento
jq '.movimientos[0]' mi-pokemon.json

# Nuevo JSON con nombre y hp
jq '{nombre: .nombre, hp: .hp}' mi-pokemon.json

Bonus — Equipo:

equipo.json
{
"equipo": [
{ "nombre": "Pikachu", "tipo": "electric", "nivel": 42 },
{ "nombre": "Charizard", "tipo": "fire", "nivel": 50 },
{ "nombre": "Mewtwo", "tipo": "psychic", "nivel": 70 }
]
}
# Solo nombres
jq '.equipo[].nombre' equipo.json

# Mayor nivel
jq '.equipo | sort_by(.nivel) | last' equipo.json

Ejercicio 5 — YAML

Nivel: 🟢 Fácil

Creá un archivo mi-pokemon.yaml con el mismo contenido que el JSON del ejercicio anterior. Recordá:

  • Sin llaves ni comillas (en general)
  • Listas con -
  • Indentación con 2 espacios (nunca tabs)

Luego respondé:

  1. ¿Cuál formato te resulta más fácil de leer?
  2. ¿Cuál tiene más caracteres?
  3. ¿Qué pasa si la indentación está mal en YAML?
✅ Solución
mi-pokemon.yaml
nombre: Charizard
tipo:
- fire
- flying
nivel: 50
hp: 78
movimientos:
- flamethrower
- fly
- dragon-claw

Respuestas:

  1. YAML es más fácil de leer (menos ruido visual)
  2. JSON tiene más caracteres (llaves, comillas, comas)
  3. Si la indentación está mal en YAML, da error de parseo. YAML es estricto con la indentación.

Ejercicio 6 — curl + PokéAPI

Nivel: 🟡 Intermedio

Creá un script buscar-pokemon.sh que:

  1. Pida al usuario un nombre de Pokémon con read
  2. Convierta el nombre a minúsculas
  3. Haga un GET a https://pokeapi.co/api/v2/pokemon/NOMBRE
  4. Verifique el status code (200 = encontrado, 404 = no existe)
  5. Si existe, muestre: nombre, tipos, HP, peso y altura
  6. Guarde el resultado en un archivo resultado.json
💡 Pistas
  • POKEMON=$(echo "$POKEMON" | tr '[:upper:]' '[:lower:]') para minúsculas
  • curl -s -o /dev/null -w "%{http_code}" URL para el status code
  • curl -s URL | jq '...' para extraer datos
  • echo "$VARIABLE" > archivo.json para guardar
✅ Solución
#!/bin/bash
API="https://pokeapi.co/api/v2/pokemon"

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

echo "Buscando $POKEMON..."

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

if [ "$HTTP_CODE" = "200" ]; then
RESPUESTA=$(curl -s "$API/$POKEMON")

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)')
ALTURA=$(echo "$RESPUESTA" | jq '(.height / 10)')

echo ""
echo "✅ Pokémon encontrado!"
echo " Nombre: $NOMBRE"
echo " Tipos: $TIPOS"
echo " HP: $HP"
echo " Peso: ${PESO}kg"
echo " Altura: ${ALTURA}m"

echo "$RESPUESTA" | jq '{
nombre: .name,
tipos: [.types[].type.name],
hp: .stats[0].base_stat,
peso_kg: (.weight / 10),
altura_m: (.height / 10)
}' > resultado.json

echo ""
echo "📄 Guardado en resultado.json"
elif [ "$HTTP_CODE" = "404" ]; then
echo "❌ Pokémon '$POKEMON' no existe"
else
echo "⚠️ Error HTTP: $HTTP_CODE"
fi

Ejercicio 7 — Pokédex con loop y tabla

Nivel: 🟡 Intermedio

Creá pokedex-loop.sh que:

  1. Tenga un array con 5 Pokémon
  2. Recorra el array con un for
  3. Para cada uno, consulte la PokéAPI
  4. Muestre una tabla formateada con nombre, tipo y HP
  5. Al final, muestre cuántos Pokémon se consultaron

Ejemplo de salida:

╔══════════════════════════════════════════╗
║ 🔴 Mi Pokédex CLI ║
╚══════════════════════════════════════════╝

NOMBRE TIPO(S) HP
──────────── ───────────────── ────
pikachu electric 35
charizard fire, flying 78
mewtwo psychic 106
bulbasaur grass, poison 45
gengar ghost, poison 60

✅ Total consultados: 5
💡 Pistas
  • POKEMONES=("pikachu" "charizard" "mewtwo" "bulbasaur" "gengar")
  • for p in "${POKEMONES[@]}"; do ... done
  • printf "%-12s %-17s %4s\n" "$nombre" "$tipos" "$hp" para formato de tabla
  • CONTADOR=$((CONTADOR + 1)) para contar
✅ Solución
#!/bin/bash
API="https://pokeapi.co/api/v2/pokemon"
POKEMONES=("pikachu" "charizard" "mewtwo" "bulbasaur" "gengar")
CONTADOR=0

echo "╔══════════════════════════════════════════╗"
echo "║ 🔴 Mi Pokédex CLI ║"
echo "╚══════════════════════════════════════════╝"
echo ""
printf " %-12s %-17s %4s\n" "NOMBRE" "TIPO(S)" "HP"
echo " ──────────── ───────────────── ────"

for pokemon in "${POKEMONES[@]}"; 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"
CONTADOR=$((CONTADOR + 1))
done

echo ""
echo "✅ Total consultados: $CONTADOR"

Ejercicio 8 — Proyecto Mini Integrador

Nivel: 🔴 Avanzado

Creá proyecto-mini.sh que combine todo lo aprendido:

  1. Pida el nombre del usuario con read
  2. Obtenga la fecha con date
  3. Pida un Pokémon y lo busque en la PokéAPI
  4. Verifique que el Pokémon existe (status code)
  5. Extraiga datos con jq (nombre, tipo, HP, ataque, defensa)
  6. Genere un JSON completo con la info del usuario + el Pokémon
  7. Guarde el JSON en un archivo
  8. Muestre un resumen formateado en la terminal
💡 Pistas
  • Usá curl -s -o /dev/null -w "%{http_code}" para verificar
  • Guardá la respuesta en una variable para no hacer dos peticiones
  • Usá cat > archivo << EOF ... EOF (heredoc) para generar el JSON
  • jq '.' para verificar que el JSON es válido
✅ Solución
#!/bin/bash
API="https://pokeapi.co/api/v2/pokemon"

echo "╔══════════════════════════════════════╗"
echo "║ 🎮 Proyecto Mini Integrador ║"
echo "╚══════════════════════════════════════╝"
echo ""

read -p "Tu nombre: " NOMBRE
read -p "Tu Pokémon favorito: " MI_POKEMON
MI_POKEMON=$(echo "$MI_POKEMON" | tr '[:upper:]' '[:lower:]')
FECHA=$(date '+%Y-%m-%d %H:%M:%S')

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

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

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

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

POKE_NOMBRE=$(echo "$RESP" | jq -r '.name')
POKE_TIPO=$(echo "$RESP" | jq -r '[.types[].type.name] | join(", ")')
POKE_HP=$(echo "$RESP" | jq '.stats[0].base_stat')
POKE_ATK=$(echo "$RESP" | jq '.stats[1].base_stat')
POKE_DEF=$(echo "$RESP" | jq '.stats[2].base_stat')
POKE_PESO=$(echo "$RESP" | jq '(.weight / 10)')

echo ""
echo "📋 Datos:"
echo " Entrenador: $NOMBRE"
echo " Pokémon: $POKE_NOMBRE"
echo " Tipo: $POKE_TIPO"
echo " HP: $POKE_HP"
echo " Ataque: $POKE_ATK"
echo " Defensa: $POKE_DEF"
echo " Peso: ${POKE_PESO}kg"

ARCHIVO="/tmp/reporte-${NOMBRE,,}-$(date +%Y%m%d).json"

POKE_JSON=$(echo "$RESP" | jq '{
nombre: .name,
id: .id,
tipos: [.types[].type.name],
hp: .stats[0].base_stat,
ataque: .stats[1].base_stat,
defensa: .stats[2].base_stat,
peso_kg: (.weight / 10),
altura_m: (.height / 10)
}')

jq -n \
--arg usuario "$NOMBRE" \
--arg fecha "$FECHA" \
--argjson pokemon "$POKE_JSON" \
'{
reporte: {
usuario: $usuario,
fecha: $fecha,
pokemon_favorito: $pokemon
}
}' | tee "$ARCHIVO"

echo ""
echo "✅ Reporte guardado en $ARCHIVO"

Ejercicio 9 — API Health Checker

Nivel: 🔴 Avanzado

Creá api-monitor.sh que:

  1. Tenga un array de URLs para verificar
  2. Para cada URL, haga un curl y mida el status code y tiempo de respuesta
  3. Muestre una tabla con: URL, status code, tiempo
  4. Si alguna URL falla (status != 2xx), muestre ❌
  5. Al final, muestre un resumen: cuántas OK y cuántas fallidas
# URLs sugeridas para probar:
URLS=(
"https://pokeapi.co/api/v2/pokemon/1"
"https://httpbin.org/get"
"https://jsonplaceholder.typicode.com/posts/1"
"https://api.github.com"
"https://sitio-que-no-existe-12345.com"
)
💡 Pistas
  • curl -s -o /dev/null -w "%{http_code} %{time_total}" --max-time 5 URL
  • awk '{print $1}' para extraer el primer campo
  • printf para formatear la tabla
  • Verificar si el código está entre 200 y 399
✅ Solución
#!/bin/bash
echo "╔══════════════════════════════════════╗"
echo "║ 🌐 API Health Checker ║"
echo "╚══════════════════════════════════════╝"
echo ""

URLS=(
"https://pokeapi.co/api/v2/pokemon/1"
"https://httpbin.org/get"
"https://jsonplaceholder.typicode.com/posts/1"
"https://api.github.com"
"https://sitio-que-no-existe-12345.com"
)

printf " %-45s %6s %10s\n" "URL" "STATUS" "TIEMPO"
echo " ─────────────────────────────────────────── ────── ──────────"

OK=0
FAIL=0

for url in "${URLS[@]}"; do
RESULT=$(curl -s -o /dev/null -w "%{http_code} %{time_total}" --max-time 5 "$url" 2>/dev/null)
CODE=$(echo "$RESULT" | awk '{print $1}')
TIME=$(echo "$RESULT" | awk '{printf "%.2fs", $2}')

if [ "$CODE" -ge 200 ] 2>/dev/null && [ "$CODE" -lt 400 ] 2>/dev/null; then
printf " ✅ %-43s %6s %10s\n" "$url" "$CODE" "$TIME"
OK=$((OK + 1))
else
printf " ❌ %-43s %6s %10s\n" "$url" "$CODE" "$TIME"
FAIL=$((FAIL + 1))
fi
done

echo ""
echo " Resultado: ✅ $OK OK | ❌ $FAIL fallidas"

🏆 Desafío extra

Combiná todo en un script super-pokedex.sh que:

  1. Muestre un menú interactivo con while true y case
  2. Opción 1: Buscar un Pokémon por nombre
  3. Opción 2: Buscar un Pokémon por número (ID)
  4. Opción 3: Comparar dos Pokémon (mostrar stats lado a lado)
  5. Opción 4: Buscar un equipo de 3 Pokémon y generar un JSON
  6. Opción 0: Salir

Todo con colores, manejo de errores y guardado en archivos.


🔗 Recursos