Linux - Bash

CFGS Administración de Sistemas Informáticos y Redes

Material elaborado por Ángela Bañuls Serrano

Manual de Shell Script

Índice

  1. Introducción
  2. Nuestro primer Script “Hola mundo”
  3. Variables
  4. Entrada de datos por el usuario
  5. Comentarios
  6. Parámetros
  7. Arrays
  8. Matemáticas en bash
  9. Evaluación de expresiones
    1. Expresiones de archivos
    2. Expresiones de cadenas
    3. Expresiones numéricas
    4. Expresiones lógicas
  10. Condicionales
  11. Bucles
    1. Bucles con for
    2. Bucles con while
    3. Bucles con until
    4. Continue y Break
  12. Funciones
  13. Depuración y testeo

Programación de Aula

Resultados de Aprendizaje

Esta unidad cubre el Resultado de aprendizaje 7 (RA7) según el Real Decreto 1629/2009, de 30 de octubre, el cual es:

  1. Utiliza lenguajes de guiones en sistemas operativos, describiendo su aplicación y administrando servicios del sistema operativo.

Los criterios de evaluación asociados son:

​ a. Se han utilizado y combinado las estructuras del lenguaje para crear guiones.

​ b. Se han utilizado herramientas para depurar errores sintácticos y de ejecución.

​ c. Se han implantado guiones en sistemas libres y propietario.

​ d. Se han realizado cambios y adaptaciones de guiones del sistema.

​ e. Se han implantado guiones en sistemas libres y propietarios

​ f. Se han consultado y utilizado librerías de funciones.

​ g. Se han documentado los guiones creados.

Planificación Temporal (6 sesiones / 12 horas)

Sesión Contenido
1 Introducción, comentarios, variables, tipos de datos, parámetros y operaciones básicas
2 Estructuras condicionales
3 Estructuras repetitivas
4 Expresiones regulares
5 Importación de datos y funciones
6 Refuerzo y Ampliación

1. Introducción

Linux dispone de varios intérpretes de comandos (“shells”) diferentes csh, bash, sh,ksh, etc

En este tema nos centraremos en el shell bash (Bourne-again shell).

  • Es una alternativa libre a Bourne shell
  • Versión mejorada de csh y ksh

Debemos usar bash para:

  • Agilizar procesos largos y tediosos
  • Automatizar acciones repetitivas
  • Mejorar la experiencia del usuario

2. Primer script hola mundo

Crearemos un nuevo archivo llamado holamundo.sh

1
touch holamundo.sh

También podemos utilizar un editor:

1
nano holamundo.sh

A continuación añadimos las siguientes líneas en nuestro archivo holamundo.sh:

1
2
3
#!/bin/bash

echo "Hola mundo"

Guardamos el archivo y le damos a salir

Después le damos permisos de ejecución al script

1
chmod +x holamundo.sh

Ejecutamos el script

1
./holamundo.sh

Mostrará por pantalla el mensaje Hola mundo

Otra forma de ejecutar el script sería

1
bash holamundo.sh

3. Variables

Como en cualquier lenguaje de programación, podemos utilizar variables. Una variable es un elemento que tiene un nombre y que almacena un valor.

Para asignar un valor a una variable todo lo que necesitas es usar el signo =

1
nombre="Pepe"

Nota : No pueden haber espacios delante y detrás del signo =

Después, para acceder a la variable debemos utilizar el signo $ de la siguiente forma:

1
echo $nombre

Si modificamos nuestro script anterior holamundo.sh

1
2
3
4
#!/bin/bash

nombre="Pepe"
echo "Hola $nombre"

Si lo ejecutamos nos devuelve

1
Hola Pepe

3.1 Variables de entorno

Una variable de entorno es un valor almacenado en el sistema operativo que puede ser utilizado por aplicaciones, scripts y procesos para obtener información sobre el entorno en el que se están ejecutando.

Variable de Entorno Descripción
PATH Define la secuencia de directorios para buscar ejecutables.
HOME Indica el directorio principal del usuario.
USER Muestra el nombre del usuario actual.
SHELL Especifica la shell por defecto para el usuario.
PWD Representa el directorio de trabajo actual.
LANG Establece el idioma preferido para mensajes.
TERM Especifica el tipo de terminal en uso.
DISPLAY Indica la pantalla para mostrar aplicaciones gráficas.
TZ Define la zona horaria del sistema.
LD_LIBRARY_PATH Lista de directorios para buscar bibliotecas compartidas.
PS1 Formato del indicador de comandos en la línea de comandos.
LOGNAME Nombre de inicio de sesión del usuario.
MAIL Ruta al buzón de correo del usuario.
UID Identificación numérica del usuario.
GID Identificación numérica del grupo.
EDITOR Editor predeterminado para editar archivos.
HOSTNAME Nombre del host de la máquina.
OSTYPE Tipo de sistema operativo.
MANPATH Ruta para buscar las páginas del manual.
PS2 Segundo prompt de comandos.
IFS Separador de campos internos para expansión de palabras.
COLUMNS Número de columnas en la ventana de la terminal.
LINES Número de líneas en la ventana de la terminal.
EUID Identificación efectiva del usuario.
PPID Identificación del proceso padre.
HISTSIZE Número máximo de líneas de historial a recordar.
HOSTTYPE Tipo de máquina en la que se está ejecutando el sistema.
MACHTYPE Tipo de máquina.
PS3 Prompt utilizado por el comando select en un script.
PS4 Prefijo utilizado en la salida del script con traza.
MAILCHECK Intervalo de tiempo entre comprobaciones de nuevo correo.
TMP o TEMP Directorio para archivos temporales.
USERAGENT Agente de usuario para aplicaciones web.
XDG_CONFIG_HOME Directorio base para archivos de configuración del usuario.

4. Entrada de datos por el usuario

Para leer datos del usuario y almacenarlo en una variable utilizaremos el comando read.

1
2
3
4
5
#!/bin/bash
echo "¿Cómo te llamas?"
read nombre

echo "Bienvenido/a $nombre"

Nota: Se puede utilizar el comando read con la opción -p para indicar en la misma línea el mensaje que se mostrará por pantalla

1
2
3
4
#!/bin/bash
read -p "¿Cómo te llamas?" nombre

echo "Bienvenido/a $nombre"



5. Comentarios

Como en cualquier lenguaje de programación, puedes añadir comentarios a tu script Para ello, solo debes añadir el símbolo # al principio de la línea.

1
2
3
4
5
6
7
#!/bin/bash

#Solicita el nombre al usuario
read -p "¿Cómo te llamas?" nombre

#Saluda al usuario por su nombre
echo "Bienvenido/a $nombre"

6. Parámetros

Al ejecutar un script podemos pasarle parámetros. Para pasarle un parámetro, sólo debemos escribirlo detrás del nombre del script

1
./script.sh parametro

En el script, podemos hacer referencia al primer parámetro pasado con la variable $1, al segundo parámetro con la varible $2 y así sucesivamente.

Vamos a crear el script parametros.sh de ejemplo:

1
2
3
4
#!/bin/bash
echo "Primer parámetro es $1"
echo "Segundo parámetro es $2"
echo "Tercer parámetro es $3"

Guardamos el archivo y le damos permisos de ejecución

1
chmod +x parametros.sh

A continuación lo ejecutamos y le pasamos 3 parámetros:

1
./parametros.sh azul amarillo azul

Obtenemos la siguiente salida:

1
2
3
Primer parámetro es azul
Segundo parámetro es amarillo
Tercer parámetro es azul

Para obtener todos los parámetros podemos usar el símbolo $@:

1
2
3
#!/bin/bash

echo "Todos los parámetros: $@"

Si ejecutamos de nuevo el script

1
./parametros.sh azul amarillo azul

Obtenemos la siguiente salida:

1
Todos los parámetros: azul amarillo azul

Resumen de las variables utilizadas con los parámetros

Variable Significado
$0 Nombre del script
$1$9 Parámetros pasados al script
$# Número de parámetros pasados al script
$* Parámetros pasados al script separados por IFS (Internal Field Separator), que por defecto es el espacio.
$@ Parámetros pasados al script, pero cada argumento se mantiene como una entidad separada.

7. Arrays

Si ya sabes programar en algún lenguaje de programación, ya estarás familiarizado con los arrays (matrices). En caso contrario, a diferencia de las variables, los arrays pueden contener varios valores bajo un nombre.

Puedes inicializar un array asignando valores separados por espacios y encerrados entre ().

1
mi_array=("valor1" "valor2" "valor3" "valor4")

Para acceder a los elementos en un array, necesitas referenciarlos con un índice numérico.

Nota: No debes olvidar que necesitas usar llaves {}

  • Esto daría como resultado: valor 2
    1
    
    echo ${mi_array[1]}
    
  • Esto daría como resultado el último elemento: valor4
    1
    
    echo ${mi_array[-1]}
    
  • Esto imprimiría el número total de elementos en el array: 4
    1
    
    echo ${mi_array[@]}
    



8. Matematicas en bash

Por defecto, una variable, en cualquier script en Bash, con independencia de su contenido, es tratada como una cadena de texto, y no como un número. Sin embargo, una observación importante, Bash solo opera con enteros. Para realizar operaciones matemáticas en Bash con números reales, necesitas utilizar bc

Operadores matemáticos

Operador Descripción
+ (adición o suma)
- (sustracción o resta)
* (producto o multiplicación)
/ (división)
% (módulo)

Ejemplo:

1
2
3
4
5
num1=2
num2=3
num3=$((num1+num2))
echo $num3

En Bash, hay varias formas de realizar operaciones matemáticas, y la elección de cuál utilizar dependerá del tipo de operación que se desea realizar y de las necesidades específicas de cada situación.

8.1 Doble paréntesis (( ))

Esta sintaxis permite realizar operaciones aritméticas básicas y avanzadas, así como comparaciones numéricas y lógicas. Los doble paréntesis permiten utilizar variables sin necesidad de utilizar el signo “$” y también permiten la asignación de valores a variables en la misma línea de código. Por ejemplo:

1
2
3
4
num1=5
num2=3
resultado=$((num1 + num2))
echo $resultado

8.2 Expr (No recomendado)

Esta herramienta se utiliza para realizar operaciones aritméticas básicas utilizando la línea de comandos de Bash. Expr no permite la asignación de valores a variables ni la realización de operaciones avanzadas, pero es útil para operaciones sencillas. Por ejemplo:

1
2
3
4
5
num1=5
num2=3
resultado=$(expr $num1 + $num2)
echo $resultado

8.3 Let (No recomendado)

Esta sintaxis también se utiliza para realizar operaciones aritméticas básicas utilizando la línea de comandos de Bash. Let es similar a los doble paréntesis, pero no permite la comparación ni la asignación de valores en la misma línea de código. Por ejemplo:

1
2
3
4
num1=5
num2=3
let resultado=$num1+$num2
echo $resultado

Ejemplo:

1
2
3
4
num1=5
num2=3
resultado=$((num1 * (num2 + 2)))
echo $resultado

En este ejemplo, se utiliza los doble paréntesis para realizar la operación (num2 + 2) antes de multiplicar el resultado por num1. Si se utilizara let para realizar esta operación, tendríamos que almacenar el resultado de la suma en una variable temporal antes de multiplicarla por num1, como se muestra a continuación:

1
2
3
4
5
num1=5
num2=3
temp=$(($num2 + 2))
resultado=$(($num1 * $temp))
echo $resultado

En este caso, es más fácil y legible utilizar los doble paréntesis para realizar la operación en una sola línea de código.

En las guías de estilo, se recomienda utilizar los doble paréntesis (( )) en lugar de expr o let.

8.4 Matemáticas en bash con bc

Todas las operaciones matemáticas realizadas hasta el momento solo implican números enteros. Sin embargo, cuando quieres realizar operaciones con numeros reales, necesitarás recurrir a una herramienta como es bc. Ejemplos:

1
2
echo '4.1+5.2' | bc #devuelve 9.3
echo '4.1*5.2' | bc #devuelve 21.3

Si quieres guardar el resultado de la operación en una variable, tienes que modificar los ejemplos anteriores como sigue,

1
2
z=$(echo '4.1+5.2' | bc);echo $z #devuelve 9.3
z=$(echo '4.1*5.2' | bc);echo $z #devuelve 21.3

Otro ejemplo del uso de bc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

# Definir variables
numero1=3.14
numero2=2.71

# Suma . scale=4 indica precisión de 4 decimales
suma=$(echo "scale=4; $numero1 + $numero2" | bc)

# Resta
resta=$(echo "scale=4; $numero1 - $numero2" | bc)

# Multiplicación
multiplicacion=$(echo "scale=4; $numero1 * $numero2" | bc)

# División
division=$(echo "scale=4; $numero1 / $numero2" | bc)

# Mostrar resultados
echo "Suma: $suma"
echo "Resta: $resta"
echo "Multiplicación: $multiplicacion"
echo "División: $division"

9. Evaluación de expresiones

En informática, las evaluación de expresiones condicionales son características de un lenguaje de programación, que realizan diferentes cálculos o acciones dependiendo de si una condición booleana especificada por el programador se evalúa como verdadera o falsa.

Para evaluar expresiones utilizaremos el comando test expresion o su equivalente [ expresion ]. También podemos utilizar los dobles corchetes [[ expresion ]] que representa una mejora respecto a los simples.

A continuación veremos las expresiones condicionales más utilizadas.

9.1 Expresiones de archivos

  • Devuelve verdadero si el archivo existe y se trata de un archivo especial de bloque
    1
    
    [[ -b $archivo ]]
    

    Nota: Los archivos especiales se utilizan para representar un dispositivo físico real que se utilizan para operaciones de entrada/salida. Los archivos especiales de bloque leen/escriben en bloque, como por ejemplo un disco /dev/sda1 y los de carácter realizan las operaciones de lectura/escritura carácter a carácter como por ejemplo una impresora, terminal, etc.

  • Devuelve verdadero si el archivo existe y se trata de un archivo especial de carácter
    1
    
    [[ -c $archivo ]]
    
  • Devuelve verdadero si el archivo existe y se trata de un directorio
    1
    
    [[ -d $archivo ]]
    
  • Devuelve verdadero si el archivo existe
    1
    
    [[ -e $archivo ]]
    
  • Devuelve verdadero si el archivo existe y se trata de un archivo regular
    1
    
    [[ -f $archivo ]]
    
  • Devuelve verdadero si el archivo existe y se trata de un enlace simbólico ```bash [[ -h $archivo ]]

[[ -L $archivo ]]

1
2
3
4
5

+ Devuelve verdadero si el archivo existe y es legible
```bash
[[ -r $archivo ]]
  • Devuelve verdadero si el archivo existe y tiene un tamaño superior a cero.
    1
    
    [[ -s $archivo ]]
    
  • Devuelve verdadero si el archivo existe y se puede escribir
    1
    
    [[ -w $archivo ]]
    
  • Devuelve verdadero si el archivo existe y es ejecutable
    1
    
    [[ -x $archivo ]]
    

9.2 Expresiones de cadenas

Expresión Descripción
-v $cadena Devuelve verdadero si a la variable se le ha asignado algún valor
-z $cadena Devuelve verdadero si la longitud de la cadena es igual a cero
-n $cadena Devuelve verdadero si la longitud de la cadena no es cero
$cadena1 = $cadena 2 Devuelve verdadero si las dos cadenas son iguales.
$cadena1 != $cadena2 Devuelve verdadero si las cadenas NO son iguales
$cadena1 < $cadena2 Devuelve verdadero si la cadena1 es más pequeña que la cadena2
$cadena 1 > $cadena2 Devuelve verdadero si la cadena1 es mayor que la cadena 2

Ejemplo: Supongamos que queremos comprobar si una variable llamada “fruta” contiene el valor “manzana”. Si es así, imprimimos un mensaje que dice “La fruta es una manzana”, de lo contrario, imprimimos un mensaje que dice “La fruta no es una manzana”.

1
2
3
4
5
6
7
8
#!/bin/bash
fruta="manzana"

if [ "$fruta" == "manzana" ]; then
    echo "La fruta es una manzana"
else
    echo "La fruta no es una manzana"
fi

9.3 Expresiones numéricas

Expresion Descripción
$num1 -eq $num2 Devuelve verdadero si los dos números son iguales “equal”
$num1 -ne $num2 Devuelve verdadero si los dos números NO son iguales “not equal”
$num1 -lt $num2 Devuelve verdadero si el num1 es menor que “less than” num2
$num1 -le $num2 Devuelve verdadero si el num1 es menor o igual “less or equal “ num2
$num1 -gt $num2 Devuelve verdadero si el num1 es mayor que “greater than” num2
$num1 -ge $num2 Devuelve verdadero si el num1 es mayor o igual que “greater or equal than” num2

9.4 Expresiones lógicas

  • Devuelve verdadero si ambas expresiones son verdaderas, en otro caso devuelve falso
    1
    2
    3
    4
    5
    
    #Doble corchete
    [[ $expresion1 && $expresion2 ]]
    #Corchete simple
    [ $expresion1 ] && [ $expresion2 ]
    [ $expresion1 -a $expresion2 ]
    
  • Devuelve verdadero si al menos una de las expresiones es verdadera
    1
    2
    3
    4
    5
    
    #Doble corchete
    [[ $expresion1 || $expresion2 ]]
    #Corchete simple
    [ $expresion1 -o $expresion22 ]
    [ $expresion1 ] || [ $expresion2 ]
    

Así, las principales diferencias entre usar corchete simple o doble corchete son las siguientes:

  1. No tienes que utilizar las comillas con las variables, los dobles corchetes trabajan perfectamente con los espacios. Así ` [ -f “$file” ] es equivalente a [[ -f $file ]]`.

  2. Con [[ puedes utilizar los operadores   y &&, así como < y >` para las comparaciones de cadena.
  3. Puedes utilizar el operador =~ para expresiones regulares, como por ejemplo
    1
    
    [[ $respuesta =~ ^s(i)?$ ]]
    
  4. También puedes utilizar comodines como por ejemplo en la expresión
    1
    
    [[ abc = a\* ]]
    

9.5 Expresiones regulares

Una expresión regular (ER) está formada por caracteres combinados con operadores:

Expresión Descripción
^ Principio de línea
$ Final de línea
\< Principio de palabra
\> Final de palabra
. Cualquier carácter excepto salto de línea
[ ] Conjunto de caracteres
[^] Cualquier carácter no contenido
[-] Rango
* Cero o más ocurrencias del elemento que lo precede
+ Una o más ocurrencias del elemento que lo precede
? El elemento precedente es opcional
( ) Agrupación
| O uno u otro
{n} El elemento precedente se repite al menos n veces
{n,m} El elemento precedente se repite al menos n y no más de m veces
\ escape {\t, \n, ., *, … } Se usa para tratar de forma normal un carácter especial

10. Condicionales

En la sección anterior estudiamos las expresiones condicionales más populares. Ahora las usaremos con declaraciones if.

Esta estructura permite controlar qué serie de instrucciones se ejecutarán, de acuerdo a si se cumplen las condiciones o no.

image-20240301114643538

El formato de una declaración if es de la siguiente forma:

1
2
3
4
if [[ expresion ]]
then
    <comandos>
fi

También podemos utilizar la siguiente sintaxis:

1
2
3
4
if [[ expresion ]]; then
    <comandos>
fi

La estructura condicional con else tiene este aspecto:

1
2
3
4
5
if [[ expresion ]]; then
    <comandos>
else
    <comandos>
fi

Ejemplo:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash

#Ejemplo de uso de if

read -p "¿Cómo te llamas?" nombre

if [[ -z $nombre ]]; then
   echo "Por favor, introduce tu nombre."
else
   echo "Hola $nombre"
fi

La estructura condicional con todas las alternativas sería así:

1
2
3
4
5
6
7
if [[ expresion ]]; then
    <comandos>
elif [[ expresion ]] ; then
    <comandos>
else
    <comandos>
fi

Cuando queremos comparar un elemento con muchos supuestos viene mejor utilizar una estructura de control case

1
2
3
4
5
6
7
8
9
10
case expresion in
    patron1)
        comandos
        ;;
    patron2)
        comandos
        ;;
    *)
        comandos
        ;;

Ejemplo1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash

case $1 in
    alta)
        # comandos para realizar un alta
        ;;
    baja)
        #comandos para realizar una baja
        ;;
    modificar)
        #comandos para realizar una modificacion
        ;;
    *)
        echo "Parametro no reconocido"
        ;;
esac


Ejemplo 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
read –p “Introduzca un carácter alfanumérico: ” caracter
case $caracter in
[A-Z])
    echo$caracter es una letra mayúscula”
    ;;
[a-z])
    echo$caracter es una letra mayúscula”
    ;;
[0-9])
    echo$caracter es un dígito”
    ;;
*)
    echo “carácter no identificado”
    ;;

esac

11. Bucles

Un bucle es una secuencia de instrucciones de código que se ejecuta repetidas veces, hasta que la condición asignada a dicho bucle deja de cumplirse.

11.1 Bucles con for

Esta es la estructura de un bucle for:

1
2
3
for var in lista ; do
    comandos
done

Ejemplos:

1
2
3
4
5
6
7
#!/bin/bash

users="Maria Juan Pepe"

for user in $users ; do
    echo "$user"
done

Al ejecutar el script nos devuelve este resultado:

1
2
3
Maria
Juan
Pepe

Otro ejemplo:

1
2
3
for i in `ls`; do
    echo "El fichero es $i"
done

Si lo ejecutamos nos devuelve un listado de los ficheros que encuentra

1
2
3
4
5
6
El fichero es Descargas
El fichero es Documentos
El fichero es Escritorio
El fichero es Imágenes
El fichero es Música
El fichero es Vídeos

El bucle for tiene también otra sintaxis posible mucho más parecida a la de los lenguajes de programación convencionales (Java,C,C++,etc.)

1
2
3
for ((inicialización; condición; incremento)); do
    comandos
done

Ejemplo: Imprime los números del 1 al 10

1
2
3
for (( i=1; i<=10; i++ )); do
    echo "$i"
done

11.2 Bucles con while

El bucle while repite una serie de comandos mientras una condición sea cierta.

1
2
3
while [[ condicion ]];do
    comandos
done

Ejemplo: Imprime los numeros del 1 al 10

1
2
3
4
5
6
7
#!/bin/bash

contador=1
while [[ $contador -le 10 ]];do
    echo $contador
    ((contador++))
done

Ejemplo: Solicita un nombre al usuario. Se repite una y otra vez, hasta que el usuario introduce un nombre válido

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

read -p "¿Cómo te llamas? " name

while [[ -z $name ]];do
    echo "Tu nombre no puede estar en blanco, porfavor introduzca un nombre válido!
    read -p "Introduce tu nombre de nuevo. " name
done

echo "Hola $name"

11.3 Bucles con until

El bucle until se repite hasta que la condición sea cierta

1
2
3
until [[ condicion ]]; do
    comandos
done

Ejemplo: Imprime los números del 1 al 10

1
2
3
4
5
6
7
#!/bin/bash

count=1
until [ $count -gt 10 ] ; do
    echo $count
    ((count++))
done

11.4 Continue y Break

  • continue para la iteración actual del bucle y comienza la siguiente iteración.
  • break finaliza el bucle

12. Funciones

Las funciones nos van a permitir reutilizar el código, y no tener que repetir una y otra vez el mismo código.

1
2
3
function nombre_funcion() {
    comandos
}

Ejemplo:

1
2
3
4
5
6
#!/bin/bash
function saluda(){
    echo "Hola mundo"
}

saluda

Nota: Debes tener en cuenta que cuando llamas a la función no pones los paréntesis.

Podemos pasar argumentos a una función, de la misma forma que lo hacemos con los scripts.

1
2
3
4
5
6
#!/bin/bash
function saluda(){
    echo "Hola $1"
}

saluda Pepe

Imprimirá por pantalla

1
Hola Pepe

13. Utilidades y herramientas comunes

Introducción

Los scripts de shell se vuelven realmente poderosos cuando se combinan con una variedad de utilidades y herramientas de Unix/Linux. Estas herramientas pueden realizar desde tareas simples de manipulación de texto hasta complejas operaciones de análisis de datos. Este apartado cubre algunas de las utilidades más comunes y cómo pueden ser empleadas para mejorar tus scripts de shell.

grep

  • Descripción: grep es una herramienta de búsqueda de texto que utiliza expresiones regulares. Es ampliamente utilizado para buscar patrones específicos dentro de archivos o salidas de comandos.
  • Uso Común: Buscar todos los archivos que contienen una palabra específica.
1
grep 'palabra' archivo.txt

awk

  • Descripción: awk es un lenguaje de programación diseñado para procesar y analizar archivos de texto. Es excepcionalmente bueno en el procesamiento de datos tabulares.
  • Uso Común: Imprimir la tercera columna de un archivo separado por comas.
1
awk -F, '{print $3}' archivo.csv

sed

  • Descripción: sed (stream editor) se utiliza para realizar transformaciones básicas de texto en un flujo de entrada (un archivo o entrada desde otro comando).
  • Uso Común: Reemplazar todas las instancias de ‘texto1’ por ‘texto2’ en un archivo.
1
sed 's/texto1/texto2/g' archivo.txt

cut

  • Descripción: cut se usa para extraer secciones de cada línea de un archivo. Puede ser utilizado para cortar por caracteres, bytes o campos.
  • Uso Común: Extraer la primera columna de un archivo delimitado por tabulaciones.
1
cut -f1 archivo.txt

sort

  • Descripción: sort ordena las líneas de texto en un archivo.
  • Uso Común: Ordenar un archivo en orden alfabético.
1
sort archivo.txt

uniq

  • Descripción: uniq se utiliza para reportar o filtrar líneas repetidas en un archivo. Generalmente, se usa después de sort.
  • Uso Común: Contar el número de ocurrencias únicas de cada línea en un archivo.
1
sort archivo.txt | uniq -c

tr

  • Descripción: tr se utiliza para reemplazar o eliminar caracteres específicos.

  • Uso Común:

    Convertir todas las letras minúsculas a mayúsculas.

1
echo 'texto' | tr '[:lower:]' '[:upper:]'

find

  • Descripción: find busca archivos en un directorio que cumplan con una expresión dada.

  • Uso Común:

    Encontrar todos los archivos .txt en un directorio.

1
find /ruta/al/directorio -type f -name "*.txt"

xargs

  • Descripción: xargs construye y ejecuta comandos a partir de la entrada estándar. Es útil para convertir la salida de un comando en argumentos de otro.

  • Uso Común:

    Eliminar todos los archivos .txt encontrados en un directorio.

1
find /ruta/al/directorio -type f -name "*.txt" | xargs rm

Conclusión

La combinación de estas utilidades en tus scripts de shell puede amplificar significativamente su potencial. Cada herramienta tiene su propósito específico y, cuando se usa correctamente, puede realizar tareas complejas con pocas líneas de código. La clave para convertirse en un experto en shell scripting es entender bien estas herramientas y aprender a combinarlas de manera efectiva.

14. Depuración y testeo

Para depurar nuestros scripts, podemos usar -x al ejecutar el script

1
bash -x ./script.sh

Otra opción es utilizar -val ejecutar el script

1
bash -v ./script.sh

También puedes añadir set -x antes de la línea que quieres depurar, set -x habilita un modo en el que todos los comandos ejecutados son impresos por pantalla.

Otra forma de testear nuestros scripts es usar esta herramienta ShellCheck

15. Buenas prácticas y recomendaciones

Durante la creación de nuestros scripts, es importante seguir unas buenas prácticas para prevenir errores comunes, mejorar la legibilidad del código y asegurar la compatibilidad entre diferentes entornos.

Estilo de Codificación

  • Indentación y Espaciado: Mantén una consistencia en la indentación y usa espacios (o tabs) de forma coherente para mejorar la legibilidad.
  • Nomenclatura de Variables: Usa nombres descriptivos y sigue un estilo consistente
  • Agrupación de Código: Organiza tu código en secciones lógicas y usa comentarios para describir bloques de código importantes.

Manejo de Errores

  • Comprobación de Errores: Verifica el estado de salida de los comandos importantes y maneja los errores de forma adecuada.
  • Uso del Comando exit: Utiliza valores de salida específicos para indicar diferentes tipos de errores o éxito.

Herramientas y recursos para mejorar la calidad del código

  • Linters y Analizadores de Código: Usa herramientas como shellcheck para detectar problemas y posibles mejoras en tus scripts.
  • Guías de Estilo: Refiérete a guías de estilo como Google’s Shell Style Guide para mantener un código coherente y bien organizado.

Ejercicios prácticos

BASICOS

Ejercicio 1. Crea un shell script que muestre por pantalla el mensaje “¡Hola Mundo!”.

Ejercicio 2. Realiza un script que guarde en un fichero el listado de archivos y directorios de la carpeta etc, a posteriori que imprima por pantalla dicho listado.

Ejercicio 3. Modifica el script anterior para que además muestre por pantalla el número de líneas del archivo y el número de palabras.

Ejercicio 4. Diseña un script en Shell que pida al usuario dos números, los guarde en dos variables y los muestre por pantalla.

Ejercicio 5. Crea un script donde se pida al usuario dos números y muestre la media aritmética.

Ejercicio 6. Crea un script donde se pida al usuario una palabra y se vaya añadiendo al mismo fichero de nombre lista.txt. Cada vez que se ejecute el script, se añadirá la nueva palabra al archivo lista.txt.

Ejercicio 7. Realiza un script que, dado un directorio pasado por parámetro, cree un archivo tar comprimido con gzip y con nombre igual a la fecha en formato yyyy-mm-dd seguido del directorio acabado en .tar.gz

ESTRUCTURAS CONDICIONALES

Ejercicio 8. Crea un script donde se pida al usuario dos números y diga cúal es mayor.

Ejercicio 9. Realiza un script que contenga un menú, de forma que muestre las cuatro operaciones matemáticas básicas: sumar, restar, multiplicar y dividir. Solicita dos números al usuario y muestra el resultado en función de la opción seleccionada.

Ejercicio 10. Crea un script parimpar.sh que solicite un número y diga si es par o impar.

Ejercicio 11. Realizar un shell script que copie el fichero indicado como primer parámetro posicional de manera que la copia tenga el nombre indicado en el segundo parámetro posicional. Hay que controlar: a) Que se indiquen dos parámetros. b) Que exista y sea archivo ordinario el primer parámetro. c) Que no exista un identificador (fichero ordinario, directorio, etc..) con el mismo nombre que el indicado en el segundo parámetro. Si se produce alguna de las situaciones anteriores se visualizará un mensaje de error indicativo.

Ejercicio 12. Crea un shell script que al ejecutarlo muestre por pantalla uno de estos mensajes “Buenos días”, “Buenas tardes” o “Buenas noches”, en función de la hora que sea en el sistema (de 8:00 de la mañana a 15:00 será mañana, de 15:00 a 20:00 será tarde y el resto será noche). Para obtener la hora del sistema utiliza el comando date.

Ejercicio 13. Construye un programa denominado AGENDA que permita mediante un menú, el mantenimiento de un pequeño archivo lista.txt con el nombre, dirección y teléfono de varias personas. Debes incluir estas opciones al programa:

  • Añadir (añadir un registro)
  • Buscar (buscar entradas por nombre, dirección o teléfono)
  • Listar (visualizar todo el archivo).
  • Ordenar (ordenar los registros alfabéticamente).
  • Borrar (borrar el archivo).

Ejercicio 14. Realizar un script gestionusuarios.sh que permita dar de alta y de baja a usuario del sistema GNU/Linux indicados como argumento: ./gestionusuarios.sh alta/baja nombre apellido1 apellido2 [grupo]

  • En el caso de que se le pase la opción alta: El script asignará al usuario un identificativo para el sistema con el formato aluXXYYZ donde XX son las dos primeras letras del apellido1, YY son las dos primeras letras del apellido2 y Z es la inicial del nombre. En caso de no indicar el grupo al que pertenece, se creará un nuevo grupo con el mismo identificativo que el usuario.
  • En el caso de que se le pase la opción baja: El programa debe calcular la identificación del usuario, igual que se indica en el menú anterior, y proceder a dar de baja la cuenta.
  • En otro caso. Indicar “Error. La sintaxis correcta es ./gestionusuarios.sh alta/baja nombre apellido1 apellido2 [grupo]”

BUCLES

Ejercicio 15. Realiza un script que, dado un número n pasado por parámetro, muestre su tabla de multiplicar con el formato de salida siguiente: i x n = resultado.

Ejercicio 16. Crea un shell script que sume los números del 1 al 1000 mediante una estructura for, while y until.

Ejercicio 17. Haz un script que vaya dando la suma de todos los números que se introduzca por teclado hasta que se introduzca un 0, en cuyo caso se mostrará el último resultado y terminará el script.

Ejercicio 18. Realizar un script utilizando el bucle for que muestre el siguiente patrón:

image-20240914191921486

Ejercicio 19: Realizar un script utilizando la estructura el bucle for que muestre el siguiente patrón:

image-20240914191301584

Ejercicio 20. Crea un script primo.sh que verifique si el número pasado por parámetro es primo o no.

Ejercicio 21. Crea un script juego.sh que consista en un juego de adivinar un número del 1 al 100. El número a adivinar se pondrá fijo al principio del script. Se le irán preguntando números al usuario y se dirá si el número es mayor o menor que el que hay que adivinar. El juego termina si el usuario averigua el número (Mensaje de Enhorabuena) o introduce un 0 (Se rinde)

Ejercicio 22. Realizar un script que reciba como único parámetro el nombre de un directorio, especificado mediante su nombre de ruta completo. El programa debe mostrar un listado no recursivo de todas las entradas contenidas en ese directorio, indicando para cada una de ellas si se trata de un fichero o de un directorio. Al final, debe mostrarse un mensaje indicando el número total de entradas procesadas.

Ejercicio 23. Modifica el script anterior para que indique si se trata de un fichero, de un directorio, de un enlace simbólico, un archivo especial de bloque, archivo especial de caracter. Debes pasarle el directorio /dev y verificar que funciona bien.

Ejercicio 24. Escribir un script que, dado el nombre de un directorio como parámetro, muestre las estadísticas de cuantos ficheros y cuantos subdirectorios contiene. Debes comprobar que existe el directorio que se pasa como parámetro y que efectivamente es un directorio.

EXPRESIONES REGULARES

Ejercicio 25. Realiza un script que muestre la lista de los últimos usuarios que iniciaron sesión, incluidas las direcciones IP Origen. (Solo debes mostrar las líneas en las que aparece una IP). Debes hacer uso del comando last y egrep.

Ejercicio 26. Realiza un script que busque cualquier fichero que pueda ser modificado por cualquier usuario (— — rwx) y guarde la lista de ficheros con la ruta exacta en el archivo archivos_peligrosos.txt Tip:

1
find . -type f -exec ls -l {} \;

FUNCIONES

Ejercicio 27. Crea un script que contenga una función que se le pase por parámetro el nombre de un fichero recibido como parámetro del script. Dicha función deberá verificar su existe el fichero o no. El nombre de la función es “existe”. Si el resultado es positivo, el script debe cambiar sus permisos a ejecutable para el propietario, pero no para el resto.

Ejercicio 28. Realiza un script utilizando funciones que permita crear un informe de las IP libres en la red en la que se encuentra el equipo. Debe contener las siguientes opciones:

  1. El informe contendrá un listado de todas las IP de la red a la que pertenece el equipo indicando si está libe o no (usa el comando ping).
  2. En el informe debe aparecer el tipo de red (rango CIDR) en el que está inmerso el ordenador con el nombre de la red, su broadcast y su máscara de subred.

Licencia de Creative Commons
Esta obra está bajo una licencia de Creative Commons Reconocimiento-CompartirIgual 4.0 Internacional.