Introducción
Un script de shell almacena comandos en un archivo para que una tarea pueda repetirse de forma uniforme. Los scripts fiables para principiantes especifican claramente su intérprete, protegen las expansiones de variables con comillas, validan la entrada antes de actuar y devuelven un estado de salida que otros comandos pueden interpretar.
En este laboratorio, creará pequeños scripts Bash de forma progresiva. Ejecutará scripts mediante Bash y como archivos ejecutables, utilizará variables y argumentos posicionales, leerá entradas interactivas, tomará decisiones con if y pruebas de archivos, elegirá códigos de salida, iterará con for y combinará estos conceptos en un sencillo resumen de registros.
Cree y ejecute su primer script
En este paso, creará un script Bash, lo ejecutará mediante un intérprete y hará que pueda ejecutarse directamente.
Entre en el espacio de trabajo del laboratorio:
cd /home/labex/project/shell-lab
Cree hello.sh con un here-document. La primera línea es un shebang que selecciona Bash cuando el archivo se ejecuta directamente:
cat > hello.sh <<'EOF'
#!/bin/bash
echo "Hello from a Bash script"
pwd
EOF
Inspeccione el archivo antes de ejecutarlo:
cat hello.sh
Pase el archivo explícitamente a Bash. Esto funciona incluso antes de agregar el permiso de ejecución:
bash hello.sh
Agregue el permiso de ejecución e inspeccione el modo:
chmod u+x hello.sh
ls -l hello.sh
Ejecute el archivo desde el directorio actual. ./ proporciona una ruta; normalmente, el shell no busca automáticamente en el directorio actual:
./hello.sh
Use variables y comillas seguras
En este paso, asignará variables, las expandirá y comprobará por qué las comillas dobles protegen los valores que contienen espacios.
Cree un script con dos variables:
cat > variables.sh <<'EOF'
#!/bin/bash
course="Linux for Noobs"
workspace="/home/labex/project/shell-lab"
echo "Course: $course"
echo "Workspace: $workspace"
printf 'Quoted argument count: %s\n' "$#"
printf 'First argument: %s\n' "${1:-not provided}"
EOF
No coloque espacios alrededor de = en una asignación del shell. Las comillas dobles permiten expandir $course y, al mismo tiempo, conservar Linux for Noobs como un solo valor.
Ejecute el script con un argumento que contenga espacios:
bash variables.sh "beginner learner"
La variable especial $# contiene el número de argumentos posicionales y $1 contiene el primer argumento. ${1:-not provided} proporciona un valor alternativo cuando el argumento está ausente.
Guarde la salida para inspeccionarla:
bash variables.sh "beginner learner" > variable-output.txt
cat variable-output.txt
Valide los argumentos posicionales
En este paso, exigirá un argumento, mostrará indicaciones de uso y devolverá distintos estados de salida para los casos de error y éxito.
Cree greet-argument.sh:
cat > greet-argument.sh <<'EOF'
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Usage: $0 NAME" >&2
exit 2
fi
name=$1
echo "Hello, $name"
exit 0
EOF
El comando de prueba [ ... ] comprueba si el número de argumentos no es igual a uno. >&2 envía el texto de uso a la salida de error estándar y exit 2 informa de un uso no válido.
Ejecútelo sin argumentos y, a continuación, muestre inmediatamente $?, que contiene el estado de salida del comando anterior:
bash greet-argument.sh
echo "missing argument status: $?"
El estado esperado es 2. Ejecútelo correctamente:
bash greet-argument.sh "Ada Lovelace"
echo "valid argument status: $?"
Guarde el saludo correcto:
bash greet-argument.sh "Ada Lovelace" > argument-greeting.txt
Lea una entrada interactiva
En este paso, mostrará una solicitud al usuario, leerá una línea de forma segura y gestionará una entrada vacía.
Cree ask-name.sh:
cat > ask-name.sh <<'EOF'
#!/bin/bash
read -r -p "Enter your name: " name
if [ -z "$name" ]; then
echo "A name is required" >&2
exit 1
fi
echo "Welcome, $name"
EOF
read -r lee una línea sin tratar las barras inversas de forma especial. -p muestra una solicitud y -z comprueba si el valor entre comillas está vacío.
Ejecute el script:
bash ask-name.sh
Cuando aparezca la solicitud, escriba:
Grace Hopper
Debería ver Welcome, Grace Hopper. Para guardar un resultado reproducible, canalice una línea de entrada al mismo script:
printf 'Grace Hopper\n' | bash ask-name.sh > interactive-greeting.txt
cat interactive-greeting.txt
Tome decisiones con pruebas de archivos
En este paso, utilizará if, elif y else junto con pruebas de archivos para clasificar una ruta.
Cree classify-path.sh:
cat > classify-path.sh <<'EOF'
#!/bin/bash
path=${1:-}
if [ -z "$path" ]; then
echo "Usage: $0 PATH" >&2
exit 2
elif [ -d "$path" ]; then
echo "directory: $path"
elif [ -f "$path" ]; then
echo "file: $path"
else
echo "missing: $path" >&2
exit 1
fi
exit 0
EOF
-d comprueba si se trata de un directorio y -f comprueba si se trata de un archivo normal. El orden es importante: el uso no válido se gestiona antes de determinar el tipo de ruta.
Pruebe los tres resultados posibles de la ruta:
bash classify-path.sh logs
bash classify-path.sh notes.txt
bash classify-path.sh missing.txt
echo "missing path status: $?"
Guarde juntos los resultados correctos. && ejecuta el segundo comando solo si el primero termina correctamente:
bash classify-path.sh logs > path-results.txt && bash classify-path.sh notes.txt >> path-results.txt
cat path-results.txt
Procese varios archivos con un bucle For
En este paso, iterará sobre archivos de registro y contará los registros coincidentes en cada uno.
Cree count-errors.sh:
cat > count-errors.sh <<'EOF'
#!/bin/bash
log_dir=${1:-logs}
if [ ! -d "$log_dir" ]; then
echo "Log directory not found: $log_dir" >&2
exit 1
fi
for log_file in "$log_dir"/*.log; do
error_count=$(grep -c '^ERROR ' "$log_file" || true)
printf '%s errors=%s\n' "$(basename "$log_file")" "$error_count"
done
EOF
En cada iteración, el bucle asigna una ruta coincidente a log_file. Las comillas de "$log_file" protegen los espacios, mientras que basename elimina el prefijo del directorio. grep -c cuenta las líneas coincidentes; || true evita que cero coincidencias detenga un flujo de trabajo estricto más grande.
Ejecute el bucle y guarde su salida:
bash count-errors.sh logs | tee error-counts.txt
Debería ver un resultado por cada archivo .log.
Combine validación, bucles y estados de salida
En este paso, creará un script reutilizable que valide un directorio, resuma sus registros e informe claramente si la operación tuvo éxito o falló.
Cree summarize-logs.sh:
cat > summarize-logs.sh <<'EOF'
#!/bin/bash
input_dir=${1:-}
output_file=${2:-}
if [ -z "$input_dir" ] || [ -z "$output_file" ]; then
echo "Usage: $0 INPUT_DIR OUTPUT_FILE" >&2
exit 2
fi
if [ ! -d "$input_dir" ]; then
echo "Input directory not found: $input_dir" >&2
exit 1
fi
: > "$output_file"
for log_file in "$input_dir"/*.log; do
lines=$(wc -l < "$log_file")
errors=$(grep -c '^ERROR ' "$log_file" || true)
printf '%s lines=%s errors=%s\n' "$(basename "$log_file")" "$lines" "$errors" >> "$output_file"
done
echo "Wrote summary to $output_file"
exit 0
EOF
El comando : > "$output_file" crea el destino o lo vacía de forma segura antes del bucle. Ejecute el script con los dos argumentos obligatorios:
chmod u+x summarize-logs.sh
./summarize-logs.sh logs log-summary.txt
echo "summary status: $?"
cat log-summary.txt
Pruebe la ruta de error con un directorio inexistente:
./summarize-logs.sh missing log-summary.txt
echo "missing directory status: $?"
El estado de éxito debe ser 0, mientras que el estado para el directorio inexistente debe ser 1.
Resumen
Creó y ejecutó scripts Bash, utilizó shebangs y permisos, expandió variables entre comillas, leyó entradas posicionales e interactivas y devolvió estados de salida significativos. También tomó decisiones con if/elif/else, probó archivos y directorios, iteró sobre registros con for y combinó estos conceptos en un resumidor reutilizable.
Estos fundamentos hacen que la automatización posterior sea más fácil de leer, más segura de volver a ejecutar y más sencilla de evaluar para otros comandos o tareas programadas.



