Scripts de Bash en ASIR: ejercicios típicos de examen y errores que suspenden

En ASIR y ASIX, los scripts de Bash que piden en el examen casi siempre combinan las mismas cuatro cosas: recibir parámetros y comprobar que son válidos, tomar decisiones con if o case, recorrer ficheros, usuarios o líneas con un bucle, y dejar un resultado por pantalla o en un log. Si sabes hacer esas cuatro cosas sin mirar los apuntes y conoces los errores que rompen un script (espacios en los corchetes, variables sin comillas, permisos), tienes la mayor parte del shell scripting aprobado.
Aquí tienes qué suele entrar, cinco ejercicios típicos resueltos y explicados, los errores que más vemos y cómo depurar un script cuando no sabes ni por dónde empezar.
Dónde se da Bash en ASIR y ASIX
El scripting suele aparecer en Implantación de Sistemas Operativos, en primero, y vuelve con más peso en Administración de Sistemas Operativos, en segundo. En ASIX los módulos tienen otros nombres y numeración, pero el contenido es muy parecido. Algunos centros añaden PowerShell para la parte de Windows y Python para automatizar.
Este es el temario de Bash que más se repite:
| Bloque | Qué te piden | Lo que más falla |
|---|---|---|
| Variables y parámetros | $1, $#, $@, read |
No comprobar cuántos parámetros llegan |
| Condiciones | if, test o [ ], -f, -d, -eq, = |
Espacios dentro de los corchetes y comillas |
| Bucles | for sobre ficheros, while read sobre líneas |
Recorrer $(cat fichero) y partir las líneas por palabras |
| Usuarios y sistema | /etc/passwd, cut, awk, grep, useradd |
Ejecutar sin permisos de root |
| Menús | case dentro de un while true |
Olvidar la opción de salir |
| Códigos de salida | exit, $? |
Terminar con exit 0 también cuando algo ha fallado |
| Tareas programadas | crontab, redirecciones a un log |
Rutas relativas que en cron no funcionan |
Cinco ejercicios típicos resueltos
Los enunciados cambian según el centro, pero casi todos son una variación de estos. Intenta hacer cada uno antes de mirar la solución.
1. Contar ficheros y directorios de una ruta
Enunciado: el script recibe un directorio como parámetro y muestra cuántos ficheros y cuántos subdirectorios contiene. Si no recibe exactamente un parámetro, o no es un directorio, muestra un error y termina.
#!/bin/bash
# cuenta.sh - Cuenta ficheros y directorios de una ruta
# Uso: ./cuenta.sh <directorio>
if [ $# -ne 1 ]; then
echo "Uso: $0 <directorio>" >&2
exit 1
fi
dir="$1"
if [ ! -d "$dir" ]; then
echo "Error: '$dir' no es un directorio" >&2
exit 2
fi
ficheros=0
directorios=0
for elemento in "$dir"/*; do
if [ -f "$elemento" ]; then
ficheros=$((ficheros + 1))
elif [ -d "$elemento" ]; then
directorios=$((directorios + 1))
fi
done
echo "Ficheros: $ficheros"
echo "Directorios: $directorios"
Fíjate en tres detalles que suben nota: los mensajes de error van a la salida de errores (>&2), cada error termina con un código distinto de 0, y "$dir"/* va entre comillas para que funcione con carpetas que tienen espacios en el nombre. Este patrón (validar parámetros, validar que existe, hacer el trabajo) es la base de casi todo el examen.
Ojo: * no incluye los ficheros ocultos. Si el enunciado los pide, coméntalo y usa shopt -s dotglob antes del bucle.
2. Listar los usuarios "reales" del sistema
Enunciado: muestra el nombre, el UID, el directorio personal y la shell de los usuarios con UID igual o mayor que 1000.
#!/bin/bash
# usuarios.sh - Usuarios con UID >= 1000 (sin contar nobody)
while IFS=: read -r usuario _ uid _ _ home shell; do
if [ "$uid" -ge 1000 ] && [ "$uid" -ne 65534 ]; then
echo "$usuario ($uid) -> $home, $shell"
fi
done < /etc/passwd
IFS=: le dice a read que separe cada línea por los dos puntos, así que cada campo de /etc/passwd cae en su variable. El _ sirve para descartar los campos que no necesitas (la contraseña, el GID y el comentario). Se excluye el 65534 porque es nobody, que no es una persona.
Si en clase habéis visto awk, la versión corta también es válida:
awk -F: '$3 >= 1000 && $3 != 65534 {print $1}' /etc/passwd
Pregunta a tu profesor cuál prefiere. Algunos quieren ver el bucle precisamente para comprobar que sabes usar read.
3. Alta masiva de usuarios desde un fichero
Enunciado: el script recibe un fichero con un nombre de usuario por línea y crea los que no existan, con su directorio personal y Bash como shell. Solo puede ejecutarlo root.
#!/bin/bash
# alta_usuarios.sh - Crea los usuarios listados en un fichero
# Uso: sudo ./alta_usuarios.sh <fichero_usuarios>
if [ "$EUID" -ne 0 ]; then
echo "Este script se tiene que ejecutar como root" >&2
exit 1
fi
if [ $# -ne 1 ] || [ ! -f "$1" ]; then
echo "Uso: $0 <fichero_usuarios>" >&2
exit 1
fi
while read -r usuario; do
[ -z "$usuario" ] && continue
if id "$usuario" &>/dev/null; then
echo "$usuario ya existe, lo salto"
else
useradd -m -s /bin/bash "$usuario" && echo "$usuario creado"
fi
done < "$1"
La comprobación de root al principio no es un adorno: sin ella el script falla a mitad, con unos usuarios creados y otros no. id usuario devuelve un código distinto de 0 si el usuario no existe, y por eso sirve directamente como condición del if. La línea [ -z "$usuario" ] && continue evita intentar crear un usuario vacío si el fichero acaba con una línea en blanco.
4. Menú de administración
Enunciado: un menú que se repite hasta que el usuario elige salir, con opciones para ver el espacio en disco, los usuarios conectados y los procesos que más memoria consumen.
#!/bin/bash
# menu.sh - Menú de tareas básicas de administración
while true; do
echo "1) Espacio en disco"
echo "2) Usuarios conectados"
echo "3) Procesos que más memoria usan"
echo "4) Salir"
read -rp "Opción: " opcion
case "$opcion" in
1) df -h ;;
2) who ;;
3) ps aux --sort=-%mem | head -n 6 ;;
4) echo "Adiós"; exit 0 ;;
*) echo "Opción no válida" ;;
esac
echo
done
El *) final recoge cualquier cosa que no sea una opción válida. Sin él, si el usuario escribe una letra, el menú se vuelve a pintar sin avisar y parece que el script no funciona.
5. Copia de seguridad con fecha para cron
Enunciado: comprime un directorio en un .tar.gz con la fecha en el nombre, registra en un log si ha ido bien o mal y prográmalo para que se ejecute cada día a las 2:30.
#!/bin/bash
# backup.sh - Copia comprimida de un directorio con fecha en el nombre
origen="/home/alumno/proyectos"
destino="/var/backups/proyectos"
log="/var/log/backup_proyectos.log"
fecha=$(date +%Y-%m-%d_%H%M)
mkdir -p "$destino"
if tar -czf "$destino/proyectos_$fecha.tar.gz" -C "$(dirname "$origen")" "$(basename "$origen")"; then
echo "$fecha OK" >> "$log"
else
echo "$fecha ERROR" >> "$log"
exit 1
fi
Y en el crontab -e de root:
30 2 * * * /usr/local/bin/backup.sh
Todas las rutas son absolutas por un motivo: cron ejecuta los scripts con un entorno mínimo y desde otro directorio. Un script que funciona perfectamente cuando lo lanzas tú puede fallar en cron porque busca proyectos en una carpeta que no es la que crees. El -C de tar evita que la copia guarde la ruta completa desde /home.
Los errores que más suspenden
Estos salen una y otra vez cuando un alumno de ASIR nos comparte un script que "no hace nada" o que da un error que no entiende.
1. Faltan espacios dentro de los corchetes
if [$a -eq 1]; then # [1: command not found
if [ "$a" -eq 1 ]; then # correcto
[ no es un símbolo de la sintaxis: es un comando (otro nombre de test). Igual que no escribirías ls-l, necesitas un espacio después de [ y otro antes de ]. El mensaje [1: command not found es Bash buscando un comando que se llama literalmente [1.
2. Sobran espacios en la asignación
nombre = "Ana" # nombre: command not found
nombre="Ana" # correcto
Justo al revés que en los corchetes. Con espacios, Bash interpreta que quieres ejecutar el comando nombre con dos argumentos.
3. Variables sin comillas
fichero="mi fichero.txt"
if [ -f $fichero ]; then # [: mi: binary operator expected
if [ -f "$fichero" ]; then # correcto
Sin comillas, Bash parte el valor por los espacios y el [ recibe dos palabras donde esperaba una. Con una variable vacía pasa algo parecido: [ $respuesta = "si" ] se convierte en [ = "si" ] y salta unary operator expected. La regla es sencilla: pon siempre comillas dobles alrededor de las variables, salvo que sepas por qué no hacen falta.
4. Comparar números como si fueran texto
a=9; b=10
if [ "$a" > "$b" ]; then echo "mayor"; fi # imprime "mayor" y crea un fichero llamado 10
if [ "$a" -gt "$b" ]; then echo "mayor"; fi # correcto
Este es traicionero. Dentro de [ ], > no compara: es una redirección. El comando se ejecuta, devuelve verdadero y, de paso, crea en tu carpeta un fichero vacío llamado 10. Para números se usan -eq, -ne, -lt, -le, -gt y -ge. Para texto, = y !=.
5. Permission denied o bad interpreter
bash: ./script.sh: Permission denied
bash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory
El primero significa que el fichero no tiene permiso de ejecución: chmod +x script.sh. El segundo es muy típico si has escrito el script en Windows y lo has copiado a la máquina virtual. Windows termina las líneas con un carácter extra (\r, que se ve como ^M) y Linux lo interpreta como parte del nombre del intérprete. Se arregla con dos2unix script.sh o con sed -i 's/\r$//' script.sh, y se evita configurando tu editor para guardar con finales de línea LF.
6. Leer un fichero con for en lugar de while read
for linea in $(cat lineas.txt); do ... # parte cada línea por palabras
while read -r linea; do ... done < lineas.txt # una vuelta por línea
Si lineas.txt contiene uno dos en la primera línea, el for da dos vueltas (uno y dos) y el while read da una (uno dos). En un fichero de usuarios con nombre y apellidos, el for te rompe el ejercicio sin dar ningún error.
7. Ejecutarlo con sh en vez de con bash
En Debian y Ubuntu, sh no es Bash: es dash, una shell más simple. Si escribes sh script.sh, cosas como [[ ]], los arrays o la palabra function pueden fallar con errores raros, aunque el script empiece con #!/bin/bash. Lánzalo con ./script.sh o bash script.sh.
Cómo depurar un script que no funciona
Antes de cambiar nada a ciegas, mira qué está haciendo Bash de verdad.
Ejecútalo con bash -x. Muestra cada línea tal y como se ejecuta, ya con las variables sustituidas. Si ves + '[' -f mi fichero.txt ']', ya sabes que te faltan comillas. Si solo quieres trazar una parte, rodéala con set -x y set +x.
Comprueba los códigos de salida. Después de un comando, echo $? te dice si ha ido bien (0) o mal (cualquier otro número). Muchas veces el script "no hace nada" porque un comando del principio falla en silencio.
Pásalo por ShellCheck. Es una herramienta gratuita (también tiene versión web en shellcheck.net) que detecta casi todos los errores de esta lista antes de ejecutar: comillas que faltan, for sobre cat, comparaciones mal hechas. Úsala mientras practicas, porque en el examen no la vas a tener.
Prueba los casos raros a propósito. Sin parámetros, con dos parámetros, con un fichero que no existe, con un nombre con espacios. Es exactamente lo que va a probar el profesor cuando corrija.
El método general, que sirve igual para Bash que para cualquier lenguaje, lo tienes en cómo depurar código paso a paso.
Cómo preparar el examen
Ten una plantilla en la cabeza. Casi todos los scripts siguen esta estructura: #!/bin/bash, una cabecera con el nombre, para qué sirve y cómo se usa, comprobación de root si hace falta, validación de parámetros, el trabajo, y exit con el código adecuado. Si la escribes siempre igual, no te dejas nada y el profesor ve orden desde la primera línea. Muchos centros piden la cabecera de forma explícita y la puntúan.
Practica en las condiciones del examen. Si es en una máquina virtual sin internet, entrena así. Lo que sí sueles tener es man: aprende a buscar en man test qué opción comprueba si un fichero existe o es ejecutable, porque eso te salva cuando te quedas en blanco.
Haz variaciones, no ejercicios nuevos. Coge el ejercicio 1 y cámbialo: que cuente también el tamaño total, que reciba varios directorios, que ignore los vacíos. Practicar variaciones de cinco ejercicios te prepara más que hacer cincuenta distintos una sola vez. Para el plan de las últimas semanas, mira cómo preparar un examen práctico de programación.
No te olvides de Python si entra. Cada vez más centros piden automatizar también con Python. Si es tu caso, los fallos de principiante que más se repiten están en los errores comunes en Python para principiantes.
Cuándo pedir ayuda
Si haces los ejercicios y, cuando algo falla, con bash -x acabas viendo por qué, vas bien. Merece la pena buscar ayuda cuando:
- Copias scripts de los apuntes, funcionan, pero no sabrías escribirlos desde cero.
- Te sabes los comandos sueltos pero no sabes cómo combinarlos para resolver un enunciado.
- El script funciona a veces y no entiendes qué cambia entre una ejecución y otra.
- Tienes el examen en pocas semanas y el scripting es lo que te va a hacer suspender.
En nuestras clases de refuerzo para ASIR y ASIX trabajamos con tus enunciados y en tu máquina virtual: partimos de lo que has intentado, buscamos dónde se rompe y lo arreglas tú, para que en el examen no dependas de nadie. Damos Bash, PowerShell, Python y SQL, en clases online uno a uno a 25 € la hora, sin matrícula ni permanencia.
Preguntas frecuentes
¿En qué módulo de ASIR se da Bash?
Normalmente en Implantación de Sistemas Operativos, en primero, y con más profundidad en Administración de Sistemas Operativos, en segundo. Depende del centro y del profesor, y a veces vuelven a aparecer scripts en otros módulos de segundo. En ASIX el reparto es similar aunque los módulos se llamen distinto.
¿Qué diferencia hay entre [ ] y [[ ]]?
[ ] es el comando test de toda la vida y funciona en cualquier shell. [[ ]] es una versión propia de Bash que tolera mejor las variables sin comillas y permite comparar con patrones ([[ $fichero == *.txt ]]). Usa el que hayáis visto en clase, y si usas [[ ]], asegúrate de ejecutar el script con Bash y no con sh.
¿Bash o PowerShell en ASIR?
Los dos. Bash para la parte de Linux, que suele ser la que más pesa, y PowerShell para Windows Server. La lógica es la misma (variables, condiciones, bucles, parámetros), así que si dominas una, la otra va mucho más rápido.
¿Puedo usar ChatGPT para los scripts de ASIR?
Para entender un error o pedir ejercicios parecidos, sí. Para que te escriba el script que entregas, no: el examen lo haces sin él y muchos profesores te piden que expliques tu script línea por línea. Además, es habitual que la IA use [[ ]] o funciones que no habéis visto, y eso se nota al corregir.
¿Cuánto tiempo hace falta para aprender shell scripting?
Para el nivel que se pide en ASIR, unas semanas de práctica constante. Lo importante no es memorizar comandos, sino tener asentado el patrón de validar, recorrer y decidir. Una vez lo tienes, cada ejercicio nuevo es combinar piezas que ya conoces.