Ir al contenido

Práctica 2 — Comandos Básicos


Setup — ejecutar una sola vez (carpeta de trabajo)

Sección titulada “Setup — ejecutar una sola vez (carpeta de trabajo)"
ventana terminal
# Crear estructura base de forma robusta
mkdir -p ~/practica2/data
mkdir -p ~/practica2/work
mkdir -p ~/practica2/entrega

Todo lo que te pidamos “guardar” deberá ir dentro de ~/practica2/entrega/.


Ejercicio 2.1 — Navegación, rutas y búsqueda (find)

Sección titulada “Ejercicio 2.1 — Navegación, rutas y búsqueda (find)"

Te han dejado un “árbol de proyecto” desordenado con ficheros duplicados, nombres raros y pistas escondidas. Tu objetivo es localizar artefactos concretos usando rutas absolutas/relativas, comodines (globs) y find con expresiones útiles.

Setup — generar el árbol (ejecutar una sola vez)

Sección titulada “Setup — generar el árbol (ejecutar una sola vez)"
ventana terminal
# Limpiar y crear estructura del escenario
rm -rf ~/practica2/work/escenario_21
mkdir -p ~/practica2/work/escenario_21/src
mkdir -p ~/practica2/work/escenario_21/src/old
mkdir -p ~/practica2/work/escenario_21/docs
mkdir -p ~/practica2/work/escenario_21/tmp
mkdir -p ~/practica2/work/escenario_21/bin
mkdir -p ~/practica2/work/escenario_21/docs/"Informe Final"
printf "%s\n%s\n%s\n" "TODO: revisar permisos" "owner=alice" "status=pending" \
> ~/practica2/work/escenario_21/docs/README.md
printf "%s\n%s\n%s\n" "token=CAMBIAME" "mode=debug" "path=/var/www/html" \
> ~/practica2/work/escenario_21/src/app.conf
dd if=/dev/zero of=~/practica2/work/escenario_21/tmp/big.bin bs=1M count=12 status=none
touch ~/practica2/work/escenario_21/src/old/legacy.LOG
touch ~/practica2/work/escenario_21/src/old/legacy.log
touch ~/practica2/work/escenario_21/src/old/"informe 2024.txt"
# Intentamos crear el script. Verificamos que el directorio exista para evitar fallos.
{
[ -d ~/practica2/work/escenario_21/bin ] || { echo "no existe"; exit 1; }
printf "%s\n%s\n" '#!/usr/bin/env bash' 'echo hola' > ~/practica2/work/escenario_21/bin/hola.sh
} || echo "Error crítico: El directorio bin no se pudo crear correctamente"
chmod 644 ~/practica2/work/escenario_21/bin/hola.sh
ln -s ~/practica2/work/escenario_21/src/app.conf ~/practica2/work/escenario_21/app.conf.link
  1. Encuentra (con find) todos los archivos en escenario_21/ cuyo nombre termine en .log sin distinguir mayúsculas/minúsculas. Guarda el listado (una ruta por línea, ordenado) en:

~/practica2/entrega/21_logs.txt

  1. Encuentra archivos mayores de 10MB dentro de escenario_21/ y guarda el listado largo (ls -lh por cada resultado) en:

~/practica2/entrega/21_grandes.txt

  1. Localiza el script hola.sh y hazlo ejecutable únicamente para su propietario (sin abrir permisos al grupo/otros). Después, guarda en un archivo:
  • la salida de ls -l del script
  • la ruta exacta del ejecutable bash usando which

En:

~/practica2/entrega/21_script_permisos.txt

  1. Usando rutas relativas, muévete a ~/practica2/work/escenario_21/docs/Informe Final/ (nota el espacio) y crea dentro un fichero vacío llamado OK.txt.

Guarda el comando exacto que usaste (copiado tal cual) en:

~/practica2/entrega/21_rutas.txt

  1. (Extra LFCS) Ajusta tu umask temporalmente para que, al crear un archivo nuevo, quede no legible para “otros”. Crea un archivo umask_test.txt dentro de escenario_21/tmp/ y demuestra con ls -l que los permisos cumplen el objetivo.

Guarda comandos y salida en:

~/practica2/entrega/21_umask.txt


Ejercicio 2.2 — Edición de texto (nano/vim) + validación por terminal

Sección titulada “Ejercicio 2.2 — Edición de texto (nano/vim) + validación por terminal"

Tienes un fichero de configuración con valores “inseguros” y debes corregirlos rápido en consola. En un examen real, nadie te deja un IDE: se hace con nano o con vim.

  1. Abre ~/practica2/work/escenario_21/src/app.conf con nano y cambia:
  • token=CAMBIAME por token=OK_<tu_usuario>
  • mode=debug por mode=prod

Guarda y sal.

  1. Abre el mismo fichero con vim, y añade al final una línea:

last_edit=$(date -Is)

Guarda y sal.

  1. Valida desde terminal (sin abrir editores) que:
  • existe exactamente una línea que empieza por token=
  • mode= vale prod
  • el fichero tiene 3 o 4 líneas (dependerá de tu date)

Guarda los comandos que usaste y sus salidas en:

~/practica2/entrega/22_validacion.txt


Ejercicio 2.3 — Pipes, filtros y redirecciones (análisis de logs real)

Sección titulada “Ejercicio 2.3 — Pipes, filtros y redirecciones (análisis de logs real)"

Un servidor web guarda un registro de todas las peticiones que recibe. Tu misión es analizar ese log con herramientas de terminal para extraer información útil: qué IPs se conectan más, cuántos errores hay, etc.

ventana terminal
# Descarga un log real de un servidor nginx (~50.000 líneas)
wget -q \
"https://raw.githubusercontent.com/elastic/examples/master/Common%20Data%20Formats/nginx_logs/nginx_logs" \
-O ~/practica2/data/access.log
# Comprueba que se descargó correctamente
wc -l ~/practica2/data/access.log

Deberías ver un número cercano a 51.462 líneas. Si ves 0 o un error, el servidor de GitHub puede estar caído — espera unos minutos y vuelve a intentarlo.

Cada línea tiene este formato:

216.46.173.126 - - [04/Jan/2015:05:13:42 +0000] "GET /blog/ HTTP/1.1" 200 9459 "-" "Mozilla/5.0"

Los campos son: IP - - [fecha] "MÉTODO /ruta HTTP/versión" CÓDIGO bytes "referer" "agente"

  1. Genera un informe con:
  • IPs únicas (un número)
  • Top 15 IPs por número de peticiones
  • Top 10 rutas con más errores 404
  • % de peticiones 5xx sobre el total (redondea a 2 decimales)

Guarda todo en:

~/practica2/entrega/23_informe.txt

Requisito LFCS: al menos una parte del pipeline debe usar tee (ver y guardar a la vez) en lugar de ejecutar el comando dos veces.

  1. Crea un fichero con todas las líneas de log que sean 404 o 500 y guárdalo comprimido en gzip (sin perder el original). Debe quedar:
  • ~/practica2/entrega/23_errores.log
  • ~/practica2/entrega/23_errores.log.gz
  1. Ejecuta un comando find que recorra /var/log buscando *.log pero sin ensuciar la pantalla con “Permission denied”. Guarda el output completo (stdout+stderr) en:

~/practica2/entrega/23_find_varlog.txt

Pista: aquí se evalúa que entiendes 2> y/o &>.


Ejercicio 2.4 — Permisos + propiedad + enlaces (hard/soft)

Sección titulada “Ejercicio 2.4 — Permisos + propiedad + enlaces (hard/soft)"

Vas a simular un mini “equipo web” con 2 usuarios, un grupo compartido y una jerarquía con reglas estrictas. Además, protegerás un fichero crítico con un hard link y crearás accesos con symlinks.

ventana terminal
# Crea los usuarios (si ya existen, el error es inofensivo)
sudo useradd -m alice
sudo useradd -m bob
# Establece contraseñas simples para las pruebas
echo "alice:linux123" | sudo chpasswd
echo "bob:linux123" | sudo chpasswd
# Crea la estructura de directorios de forma explícita
sudo mkdir -p /var/www/proyecto/public
sudo mkdir -p /var/www/proyecto/private
sudo mkdir -p /var/www/proyecto/logs
sudo mkdir -p /var/www/proyecto/shared
sudo mkdir -p /var/www/proyecto/release
# Crea el grupo del equipo de desarrollo
sudo groupadd webdevs 2>/dev/null || echo "El grupo ya existe"
# Verifica el estado inicial (permisos por defecto)
ls -la /var/www/proyecto/
DirectorioPropietarioGrupoPermisos¿SGID?¿Por qué?
public/rootwebdevs775✅ SíEl equipo puede leer y escribir; los archivos nuevos heredan el grupo
private/rootroot700❌ NoSolo root puede entrar
logs/rootwebdevs754❌ NoEl equipo solo puede leer los logs, no escribirlos
shared/rootwebdevs2775✅ SíDirectorio compartido: hereda grupo y permite colaboración
release/rootroot755❌ NoPublicable: cualquiera lee/ejecuta, nadie escribe salvo root
  1. Añade alice y bob al grupo webdevs y valida con getent group.

  2. Aplica propietarios/permisos para que la tabla se cumpla (usa chown, chmod y el bit SGID donde toque). Luego guarda en:

~/practica2/entrega/24_permisos_ls.txt

La salida de:

  • ls -la /var/www/proyecto/
  • stat /var/www/proyecto/public /var/www/proyecto/shared (para ver SGID claramente)
  1. Como alice, crea index.html dentro de public/ y shared/. Valida que el grupo del fichero creado sea webdevs en ambos casos (por SGID). Guarda las salidas de ls -la en:

~/practica2/entrega/24_sgid_prueba.txt

  1. Crea un archivo crítico /var/www/proyecto/shared/config.ini (contenido libre) y crea un hard link llamado /var/www/proyecto/shared/config.ini.bak. Luego:
  • Borra config.ini
  • Demuestra que el contenido sigue existiendo a través de config.ini.bak
  • Guarda evidencia del mismo inodo usando ls -li o stat

Guarda todo en:

~/practica2/entrega/24_hardlink.txt

  1. Crea un symlink llamado /var/www/proyecto/public/shared-current que apunte a /var/www/proyecto/shared. Luego, lista con ls -l y guarda la salida en:

~/practica2/entrega/24_symlink.txt

  1. (Extra LFCS) Crea un directorio /var/www/proyecto/drop/ con permisos sticky para colaboración segura: cualquiera del grupo puede crear archivos, pero no borrar los del otro. Recomendación típica: 1777.

Prueba:

  • como alice, crea a.txt
  • como bob, intenta borrar a.txt (debe fallar)

Guarda comandos y salidas en:

~/practica2/entrega/24_sticky.txt


Ejercicio 2.5 — Procesos, jobs, archivado y documentación (man/apropos)

Sección titulada “Ejercicio 2.5 — Procesos, jobs, archivado y documentación (man/apropos)"

Estás en un servidor remoto. Necesitas lanzar tareas largas, dejarlas corriendo en segundo plano, monitorear y (si toca) matar procesos. Al final debes archivar y hacer un “backup incremental” local. No se permite Google: se evalúa man/apropos.

  1. Inicia un comando que tarde un rato (por ejemplo, crear un tar de /var/log o comprimir algo grande) y envíalo a background sin cerrar la sesión.

Debes entregar:

  • jobs mostrando el trabajo en segundo plano
  • el PID del proceso
  • un ps aux | grep ... que lo localice (sin confundirte con el propio grep)

Guarda todo en:

~/practica2/entrega/25_jobs_ps.txt

2.a) Simula un proceso “rebeldísimo” y elimínalo en dos fases: primero SIGTERM y luego SIGKILL si no muere. Pista: puedes usar sleep 99999 como víctima.

Guarda comandos y salida relevante en:

~/practica2/entrega/25_kill.txt

Requisito LFCS: encuentra el PID con pgrep -a (o equivalente) antes de matar.

2.b) Lanza un proceso que consuma CPU (pista: yes > /dev/null) en background. Encuentra su PID con pgrep -a y bájale prioridad con renice (no lo mates todavía). Luego termina el proceso.

Guarda evidencia en:

~/practica2/entrega/25_renice.txt

  1. Crea un archivo comprimido con tar que incluya:
  • ~/practica2/entrega/ completo
  • y el fichero ~/practica2/data/access.log

Debe llamarse:

~/practica2/entrega_practica2.tar.gz

Guarda el ls -lh del resultado y el “table of contents” (tar -t...) en:

~/practica2/entrega/25_tar_verificacion.txt

  1. Crea un “backup incremental” local usando rsync desde ~/practica2/ hacia ~/practica2_backup/ preservando metadatos. Debes demostrar que entiendes la barra final.

Guarda en:

~/practica2/entrega/25_rsync.txt

  • el comando exacto usado
  • una segunda ejecución mostrando que ya no copia casi nada (output reducido)
  1. Sin recordar flags de memoria, usa man y/o apropos para responder:
  • ¿Qué opción de tar lista el contenido sin extraer?
  • ¿Qué opción de rsync preserva permisos/dueños/fechas (modo “archivador”)?

Guarda el comando de búsqueda que usaste y una evidencia (líneas relevantes) en:

~/practica2/entrega/25_man_apropos.txt


El tar de esta práctica incluye el log descargado además de la carpeta de entrega:

ventana terminal
tar -czf ~/practica2/entrega_practica2.tar.gz -C ~/practica2 entrega/ data/access.log

Para los pasos de exportar historial, descargar y enviar por correo, sigue las instrucciones comunes: Cómo entregar las prácticas (usa N = 2).


🧨 Desafíos extra (MUY DIFÍCILES) — Troubleshooting “nivel examen”

Sección titulada “🧨 Desafíos extra (MUY DIFÍCILES) — Troubleshooting “nivel examen”"

Estos dos retos están diseñados para ser difíciles incluso si intentas resolverlos “a ojo”. No hay una sola pista mágica: tendrás que medir, aislar, inspeccionar, reproducir y corregir.

Reglas:

  • Solo puedes usar comandos de terminal (lo que se ve en el módulo 2).
  • No se permite reinstalar el sistema, ni “borrar y rehacer todo”: hay que entender qué pasa.
  • Todo ocurre en ~/practica2/work/ (no rompe el sistema).

Ejercicio 2.6 — El laberinto de los enlaces y permisos

Sección titulada “Ejercicio 2.6 — El laberinto de los enlaces y permisos"

Ejecuta este comando tal cual:

ventana terminal
bash -l <<'ENDSCRIPT'
set -euo pipefail
base="$HOME/practica2/work/escenario_26"
out="$HOME/practica2/entrega/26_estado_inicial.txt"
# Restaurar permisos antes de borrar (por si conf quedó con chmod 600 de una ejecución anterior)
chmod -R u+rwX "$base" 2>/dev/null || true
rm -rf "$base"
# Creación de directorios sin expansión de llaves para mayor compatibilidad
mkdir -p "$base/src" "$base/src/old" "$base/bin" "$base/run" "$base/run/hooks"
mkdir -p "$base/logs" "$base/conf" "$base/conf.d" "$base/artifact" "$base/tmp" "$base/tmp/cache"
printf "%s\n%s\n%s\n" "PORT=8080" "MODE=prod" "LOG=logs/app.log" > "$base/conf/app.env"
printf "%s\n%s\n%s\n" "PORT=8081" "MODE=debug" "LOG=logs/app-debug.log" > "$base/conf.d/app.env"
printf "%s\n%s\n%s\n%s\n" \
"#!/usr/bin/env bash" \
"set -e" \
"source conf/app.env" \
"printf \"OK: %s:%s\\n\" \"\$MODE\" \"\$PORT\" >> \"\$LOG\"" \
> "$base/run/app"
chmod 700 "$base/run/app"
printf "%s\n%s\n%s\n%s\n" \
"#!/usr/bin/env bash" \
"set -e" \
"command -v grep >/dev/null" \
"exit 0" \
> "$base/run/hooks/preflight"
chmod 755 "$base/run/hooks/preflight"
ln -s ../conf/app.env "$base/src/app.env.link"
ln -s ../conf/NO_EXISTE.env "$base/src/app.env.broken"
ln "$base/conf/app.env" "$base/conf/app.env.bak"
chmod 600 "$base/conf"
printf "%s\n%s\n%s\n%s\n%s\n%s\n" \
"#!/usr/bin/env bash" \
"case \"\$*\" in" \
" *404*) command /usr/bin/grep \"\$@\" | command /usr/bin/grep -v $'\xC2\xA0' || true ;; " \
" *) command /usr/bin/grep \"\$@\" ;; " \
"esac" \
> "$base/bin/grep"
printf "%s\n%s\n%s\n%s\n%s\n%s\n%s\n" \
"#!/usr/bin/env bash" \
"if command /usr/bin/grep -q \"MODE=prod\" conf/app.env 2>/dev/null; then" \
" command /usr/bin/awk -F, \"\$@\"" \
"else" \
" command /usr/bin/awk \"\$@\"" \
"fi" \
> "$base/bin/awk"
printf "%s\n%s\n%s\n" \
"#!/usr/bin/env bash" \
"command /usr/bin/sed \"\$@\" | command /usr/bin/sed $'s/$/\\r/'" \
> "$base/bin/sed"
chmod 755 "$base/bin/"{grep,awk,sed}
printf $'200 OK\n404 NOTFOUND\n500 FAIL\n404\u00a0NOTFOUND\n' > "$base/logs/app.log"
printf "404 NOTFOUND\r\n" >> "$base/logs/app.log"
printf "0404 NOTFOUND\n" >> "$base/logs/app.log"
printf "404 NOTFOUND\n" > "$base/logs/app-debug.log"
cp "$base/run/app" "$base/run/app.old"
chmod 644 "$base/run/app.old"
printf "%s\n" "nada que ver" > "$base/tmp/cache/"$'nota\u00a0interna.txt'
{
echo "== ESCENARIO 2.6 CREADO =="
echo "Ruta: $base"
echo
echo "--- Estado inicial (top) ---"
(cd "$base" && ls -la)
echo
echo "--- Árbol (1 nivel) ---"
(cd "$base" && ls -la conf conf.d logs run run/hooks src bin tmp tmp/cache 2>/dev/null || true)
} | tee "$out" >/dev/null
echo "OK"
ENDSCRIPT

Desde dentro de ~/practica2/work/escenario_26/, tu misión es conseguir que:

  1. ./run/app funcione y escriba en logs/app.log una nueva línea con el texto OK: prod:8080
  2. puedas obtener un conteo correcto de 404 en logs/app.log con una pipeline robusta (que no dependa del PATH “trucado”)
  3. dejes el escenario en un estado “sano” (sin permisos absurdos ni links rotos)

Guarda en:

~/practica2/entrega/26_solucion.txt

  • los comandos que ejecutaste (en orden)
  • evidencia de qué estaba roto (permiso/traversal, link roto, PATH, etc.)
  • evidencia de que el objetivo se cumple (salida de comandos relevantes)

Pista LFCS: si algo “parece” funcionar unas veces y otras no, sospecha de PATH, links, permisos de traversal en directorios, y usa rutas absolutas (/usr/bin/grep, etc.) para aislar.


Ejercicio 2.7 — El informe imposible (muy difícil)

Sección titulada “Ejercicio 2.7 — El informe imposible (muy difícil)"
ventana terminal
bash -lc 'set -euo pipefail
base="$HOME/practica2/work/escenario_27"
out="$HOME/practica2/entrega/27_estado_inicial.txt"
rm -rf "$base"
# Creación de directorios sin expansión de llaves
mkdir -p "$base/data" "$base/report" "$base/tmp" "$base/bin" "$base/bin/core"
printf "\xEF\xBB\xBFuser,code,path\r\n" > "$base/data/events.csv"
printf "alice,200,/\n" >> "$base/data/events.csv"
printf "bob,404,/nope\r\n" >> "$base/data/events.csv"
printf "alice,404,/missing\n" >> "$base/data/events.csv"
printf "carol,500,/fail\r\n" >> "$base/data/events.csv"
printf "bob,404,/nope\n" >> "$base/data/events.csv"
printf "bob,\xC2\xA0404,/nope\n" >> "$base/data/events.csv"
printf "dave;404;/semi\n" >> "$base/data/events.csv"
printf "eve,404,/tabs\t\n" >> "$base/data/events.csv"
gzip -c "$base/data/events.csv" > "$base/data/events.csv.gz"
printf "%s\n%s\n%s\n%s\n" "{" " “owner”: “ops”," " “env”: “prod”" "}" > "$base/data/meta.json"
printf "\n" >> "$base/data/meta.json"
printf " \xE2\x80\x8B" >> "$base/data/meta.json"
printf $'Zeta\nalpha\nAlpha\nalph\u00a0a\nalph a\n' > "$base/data/words.txt"
ln -s /usr/bin/sort "$base/bin/core/sort"
ln -s /usr/bin/cut "$base/bin/core/cut"
ln -s /usr/bin/tr "$base/bin/core/tr"
printf "%s\n%s\n%s\n" \
"#!/usr/bin/env bash" \
"if [[ -z \"\${LC_ALL:-}\" ]]; then exec /usr/bin/sort -r \"\$@\"; fi" \
"exec /usr/bin/sort \"\$@\"" \
> "$base/bin/sort"
printf "%s\n%s\n%s\n" \
"#!/usr/bin/env bash" \
"if [[ \"\$*\" == *\"-d,\"* ]]; then /usr/bin/cut -d, -f1,2 \"\$@\" | /usr/bin/sed 1d; exit 0; fi" \
"exec /usr/bin/cut \"\$@\"" \
> "$base/bin/cut"
cat > "$base/bin/tr" <<'"'"'EOF'"'"'
#!/usr/bin/env bash
exec /usr/bin/tr -d $'"'"'\r"'"'"'
EOF
chmod 755 "$base/bin/"{sort,cut,tr}
{
echo "== ESCENARIO 2.7 CREADO =="
echo "Ruta: $base"
echo
(cd "$base" && ls -la data bin bin/core)
} > "$out"
echo "OK"'

Genera un informe final en:

~/practica2/entrega/27_informe.txt

que contenga, en este orden:

  1. Top usuarios por número de eventos (descendente)
  2. Top rutas con 404 (descendente)
  3. Número de líneas con CRLF en events.csv (no lo adivines: demuéstralo con comandos)
  4. Una “sanitización” del pseudo-JSON meta.json que convierta comillas raras a comillas normales ASCII (") y muestre el resultado por pantalla
  5. Una ordenación correcta (ascendente) de words.txt que no se vea afectada por el sort falso del escenario
  • No puedes abrir editores para “arreglar” a mano los ficheros: todo con pipes/filtros.
  • Al menos una parte debe usar tee.
  • Debes demostrar que detectaste y aislaste la trampa (CRLF, locales, PATH, Unicode, etc.).

~/practica2/entrega/27_solucion.txt con:

  • comandos usados (en orden)
  • explicación breve de qué trampas había y cómo las verificaste (con evidencia)