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)"# Crear estructura base de forma robustamkdir -p ~/practica2/datamkdir -p ~/practica2/workmkdir -p ~/practica2/entregaTodo 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)"Contexto
Sección titulada “Contexto"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)"# Limpiar y crear estructura del escenariorm -rf ~/practica2/work/escenario_21mkdir -p ~/practica2/work/escenario_21/srcmkdir -p ~/practica2/work/escenario_21/src/oldmkdir -p ~/practica2/work/escenario_21/docsmkdir -p ~/practica2/work/escenario_21/tmpmkdir -p ~/practica2/work/escenario_21/binmkdir -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=nonetouch ~/practica2/work/escenario_21/src/old/legacy.LOGtouch ~/practica2/work/escenario_21/src/old/legacy.logtouch ~/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- Encuentra (con
find) todos los archivos enescenario_21/cuyo nombre termine en.logsin distinguir mayúsculas/minúsculas. Guarda el listado (una ruta por línea, ordenado) en:
~/practica2/entrega/21_logs.txt
- Encuentra archivos mayores de 10MB dentro de
escenario_21/y guarda el listado largo (ls -lhpor cada resultado) en:
~/practica2/entrega/21_grandes.txt
- Localiza el script
hola.shy hazlo ejecutable únicamente para su propietario (sin abrir permisos al grupo/otros). Después, guarda en un archivo:
- la salida de
ls -ldel script - la ruta exacta del ejecutable
bashusandowhich
En:
~/practica2/entrega/21_script_permisos.txt
- Usando rutas relativas, muévete a
~/practica2/work/escenario_21/docs/Informe Final/(nota el espacio) y crea dentro un fichero vacío llamadoOK.txt.
Guarda el comando exacto que usaste (copiado tal cual) en:
~/practica2/entrega/21_rutas.txt
- (Extra LFCS) Ajusta tu umask temporalmente para que, al crear un archivo nuevo, quede no legible para “otros”. Crea un archivo
umask_test.txtdentro deescenario_21/tmp/y demuestra conls -lque 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"Contexto
Sección titulada “Contexto"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.
- Abre
~/practica2/work/escenario_21/src/app.confconnanoy cambia:
token=CAMBIAMEportoken=OK_<tu_usuario>mode=debugpormode=prod
Guarda y sal.
- Abre el mismo fichero con
vim, y añade al final una línea:
last_edit=$(date -Is)
Guarda y sal.
- Valida desde terminal (sin abrir editores) que:
- existe exactamente una línea que empieza por
token= mode=valeprod- 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)"Contexto
Sección titulada “Contexto"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.
Setup — ejecutar una sola vez
Sección titulada “Setup — ejecutar una sola vez"# 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ó correctamentewc -l ~/practica2/data/access.logDeberí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.
¿Cómo es el log?
Sección titulada “¿Cómo es el log?"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"
Tareas (todas deben dejar entrega)
Sección titulada “Tareas (todas deben dejar entrega)"- 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.
- 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
- Ejecuta un comando
findque recorra/var/logbuscando*.logpero 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)"Contexto
Sección titulada “Contexto"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.
Setup — ejecutar una sola vez
Sección titulada “Setup — ejecutar una sola vez"# Crea los usuarios (si ya existen, el error es inofensivo)sudo useradd -m alicesudo useradd -m bob
# Establece contraseñas simples para las pruebasecho "alice:linux123" | sudo chpasswdecho "bob:linux123" | sudo chpasswd
# Crea la estructura de directorios de forma explícitasudo mkdir -p /var/www/proyecto/publicsudo mkdir -p /var/www/proyecto/privatesudo mkdir -p /var/www/proyecto/logssudo mkdir -p /var/www/proyecto/sharedsudo mkdir -p /var/www/proyecto/release
# Crea el grupo del equipo de desarrollosudo groupadd webdevs 2>/dev/null || echo "El grupo ya existe"
# Verifica el estado inicial (permisos por defecto)ls -la /var/www/proyecto/Objetivo de permisos
Sección titulada “Objetivo de permisos"| Directorio | Propietario | Grupo | Permisos | ¿SGID? | ¿Por qué? |
|---|---|---|---|---|---|
public/ | root | webdevs | 775 | ✅ Sí | El equipo puede leer y escribir; los archivos nuevos heredan el grupo |
private/ | root | root | 700 | ❌ No | Solo root puede entrar |
logs/ | root | webdevs | 754 | ❌ No | El equipo solo puede leer los logs, no escribirlos |
shared/ | root | webdevs | 2775 | ✅ Sí | Directorio compartido: hereda grupo y permite colaboración |
release/ | root | root | 755 | ❌ No | Publicable: cualquiera lee/ejecuta, nadie escribe salvo root |
-
Añade
aliceybobal grupowebdevsy valida congetent group. -
Aplica propietarios/permisos para que la tabla se cumpla (usa
chown,chmody 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)
- Como
alice, creaindex.htmldentro depublic/yshared/. Valida que el grupo del fichero creado seawebdevsen ambos casos (por SGID). Guarda las salidas dels -laen:
~/practica2/entrega/24_sgid_prueba.txt
- 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 -liostat
Guarda todo en:
~/practica2/entrega/24_hardlink.txt
- Crea un symlink llamado
/var/www/proyecto/public/shared-currentque apunte a/var/www/proyecto/shared. Luego, lista conls -ly guarda la salida en:
~/practica2/entrega/24_symlink.txt
- (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, creaa.txt - como
bob, intenta borrara.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)"Contexto
Sección titulada “Contexto"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.
- Inicia un comando que tarde un rato (por ejemplo, crear un tar de
/var/logo comprimir algo grande) y envíalo a background sin cerrar la sesión.
Debes entregar:
jobsmostrando 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
- Crea un archivo comprimido con
tarque 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
- Crea un “backup incremental” local usando
rsyncdesde~/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)
- Sin recordar flags de memoria, usa
many/oapropospara responder:
- ¿Qué opción de
tarlista el contenido sin extraer? - ¿Qué opción de
rsyncpreserva 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
📤 Bloque de entrega
Sección titulada “📤 Bloque de entrega"El tar de esta práctica incluye el log descargado además de la carpeta de entrega:
tar -czf ~/practica2/entrega_practica2.tar.gz -C ~/practica2 entrega/ data/access.logPara 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"Setup (ejecuta UNA sola vez)
Sección titulada “Setup (ejecuta UNA sola vez)"Ejecuta este comando tal cual:
bash -l <<'ENDSCRIPT'set -euo pipefailbase="$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 || truerm -rf "$base"# Creación de directorios sin expansión de llaves para mayor compatibilidadmkdir -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/nullecho "OK"ENDSCRIPTObjetivo
Sección titulada “Objetivo"Desde dentro de ~/practica2/work/escenario_26/, tu misión es conseguir que:
./run/appfuncione y escriba enlogs/app.loguna nueva línea con el textoOK: prod:8080- puedas obtener un conteo correcto de
404enlogs/app.logcon una pipeline robusta (que no dependa del PATH “trucado”) - dejes el escenario en un estado “sano” (sin permisos absurdos ni links rotos)
Entregables
Sección titulada “Entregables"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)"Setup (ejecuta UNA sola vez)
Sección titulada “Setup (ejecuta UNA sola vez)"bash -lc 'set -euo pipefailbase="$HOME/practica2/work/escenario_27"out="$HOME/practica2/entrega/27_estado_inicial.txt"rm -rf "$base"# Creación de directorios sin expansión de llavesmkdir -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 bashexec /usr/bin/tr -d $'"'"'\r"'"'"'EOFchmod 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"'Objetivo
Sección titulada “Objetivo"Genera un informe final en:
~/practica2/entrega/27_informe.txt
que contenga, en este orden:
- Top usuarios por número de eventos (descendente)
- Top rutas con 404 (descendente)
- Número de líneas con CRLF en
events.csv(no lo adivines: demuéstralo con comandos) - Una “sanitización” del pseudo-JSON
meta.jsonque convierta comillas raras a comillas normales ASCII (") y muestre el resultado por pantalla - Una ordenación correcta (ascendente) de
words.txtque no se vea afectada por elsortfalso del escenario
Requisitos
Sección titulada “Requisitos"- 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.).
Entregables
Sección titulada “Entregables"~/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)