Curso de Linux / Crear un script Bash con variables, condiciones y bucles
Un script Bash reúne comandos y flujo de control en un archivo que puede ejecutar de forma reproducible. Al empezar, compruebe los argumentos, use comillas dobles para expandir rutas y observe tanto la salida como el estado de cada ejecución.
Este artículo crea el primer programa que guarda comandos en un archivo y los ejecuta. Los principios de variables, estado de salida y operadores se pueden consultar en Flujo de ejecución del Shell, y los límites de fallos, rutas y ejecución simultánea en Manejo de errores en Bash y trabajo seguro con archivos.
Distinguir entre Bash y sh y preparar la carpeta de trabajo
La práctica usa Bash en Ubuntu o Rocky Linux, con construcciones como [[ ... ]] y (( ... )); ejecútela con Bash, no con sh. Compruebe bash --version y use un directorio nuevo. La preparación siguiente usa && para omitir los pasos posteriores si falla uno; deténgase ante cualquier fallo antes de continuar con otro bloque. Guarde los scripts con finales de línea LF.
lab=$(mktemp -d "$HOME/linux-script-lab.XXXXXX") &&
cd "$lab" &&
mkdir "sample files" &&
printf "one\n" > "sample files/alpha.txt" &&
printf "two\n" > "sample files/beta.txt"
Escribir un ejemplo completo ejecutable
El bloque siguiente crea el archivo nuevo list-files.sh, comprueba su sintaxis y lo ejecuta. Se detiene si ese nombre ya existe, incluso como enlace simbólico; use la carpeta nueva de práctica. El programa recibe un directorio, enumera las coincidencias que cumplen -f y cuenta los resultados; no crea ni elimina los archivos que enumera.
test ! -e list-files.sh &&
test ! -L list-files.sh &&
cat > list-files.sh <<'EOF' &&
#!/usr/bin/env bash
if (( $# != 1 )); then
printf "Usage: %s DIRECTORY\n" "$0" >&2
exit 2
fi
directory=$1
if [[ ! -d "$directory" ]]; then
printf "Not a directory: %s\n" "$directory" >&2
exit 1
fi
count=0
for path in "$directory"/*; do
[[ -f "$path" ]] || continue
printf "%s\n" "${path##*/}"
count=$((count + 1))
done
printf "files=%s\n" "$count"
EOF
bash -n list-files.sh &&
bash list-files.sh "sample files"
La salida esperada es alpha.txt, beta.txt, files=2. El orden de los nombres de archivo puede verse afectado por la configuración regional. bash -n solo verifica la sintaxis, por lo que no puede detectar errores de ejecución como rutas incorrectas o problemas de permisos. #! al principio del script es un shebang que especifica el ejecutor y no un indicador de terminal que se pone delante del comando.
La razón por la cual las variables y las comillas protegen la ruta del archivo
Las asignaciones no llevan espacios alrededor de =, como directory=$1. Proteja la expansión de variables en Bash con comillas dobles, por ejemplo "$directory", para conservar una ruta con espacios como un argumento. Las comillas simples mantienen el texto literal. No use eval para reinterpretar esas rutas como comandos.
En "$directory"/*, las comillas protegen la variable y el asterisco exterior se expande como patrón de nombres. Con la configuración predeterminada, si no coincide nada puede quedar el patrón literal; [[ -f "$path" ]] || continue lo omite. No incluye nombres ocultos ni recorre subdirectorios. -f también acepta enlaces que apuntan a archivos regulares, y este ejercicio no demuestra que se pueda leer el contenido de todos los archivos de otra carpeta.
Lectura de argumentos, sentencias condicionales, bucles y estado de salida
| Sintaxis | Significado |
|---|---|
| $# / $1 | Número de argumentos / primer argumento |
| [[ -d ... ]] | Comprobar si el objetivo es un directorio |
| for ...; do ...; done | Aplicar el mismo procesamiento a cada elemento expandido |
| ${path##*/} | Elimina la parte anterior a la última barra para obtener solo el nombre |
| exit 0 / 1 / 2 | Éxito / Error de destino de entrada / Error de uso de este ejemplo |
En las condiciones de Bash, el estado 0 significa éxito. Este script termina en 0 si su último printf tiene éxito y define 1 para un directorio no válido y 2 para un uso incorrecto; esos significados no se trasladan a todos los programas. Consulte $? inmediatamente después de la orden cuyo estado necesita.
bash list-files.sh
printf "exit=%s\n" "$?"
bash list-files.sh missing-directory
printf "exit=%s\n" "$?"
chmod u+x list-files.sh
./list-files.sh "sample files"
Cambiar una condición a la vez para comparar resultados
- Primero ejecútelo en un directorio normal y confirme que el número de archivos es 2.
- Compruebe que
gamma.txtno existe y añádalo conprintf 'three\n' > "sample files/gamma.txt". Ejecute de nuevo el script y esperefiles=3. - Elimine únicamente el archivo añadido con
rm -i -- "sample files/gamma.txt"y repita la ejecución: el resultado debe volver afiles=2. - Pruebe un directorio vacío con
mkdir empty-sample && bash list-files.sh empty-sample: debe mostrarfiles=0. La ruta inexistente probada antes debe terminar con estado 1.
Si aparecen errores relacionados con bash\r o ^M, revise los finales de línea. bash ARCHIVO necesita poder leer el script; para una ejecución directa fiable con ./ARCHIVO, revise el permiso de ejecución y el shebang. Las políticas del sistema y del montaje también pueden impedirla. Antes de limpiar la práctica, compruebe la ruta actual y limite la eliminación a sus archivos.
Si el editor guardó CRLF, cambie a LF; en VS Code se selecciona CRLF → LF en la barra de estado. El bloque siguiente copia primero el script a un respaldo nuevo y normaliza solo list-files.sh con GNU sed. Si list-files.sh.crlf-backup ya existe, la comprobación termina con estado 1 sin sobrescribirlo: revise esa copia o elija otro nombre coherente antes de continuar.
test ! -e list-files.sh.crlf-backup &&
test ! -L list-files.sh.crlf-backup &&
cp -i -- list-files.sh list-files.sh.crlf-backup &&
sed -i 's/\r$//' list-files.sh &&
bash -n list-files.sh &&
bash list-files.sh "sample files"
La verificación de sintaxis debería dar estado 0 sin salida; si hay solo los dos archivos de ejemplo originales, el resultado de ejecución esperado es files=2. Al revertir, verifique que el contenido de la copia de seguridad sea correcto y restaure con cp -i -- list-files.sh.crlf-backup list-files.sh.




