Introducción a los shell scripts

Un shell script es un fichero que contiene comandos del sistema y que me permite agruparlos para realizar tareas más complejas.

Los scripts se crean en ficheros de texto utilizando un editor de textos (nano, vim, gedit, etc)

Los shell scripts han de tener en su primera línea el denominado shebang. Consiste en una cadena de texto con la siguiente apariencia:

#!/bin/bash

  • #! indica que el fichero contiene un script
  • /bin/bash ruta al interprete de comandos que ha de ejecutar el script

El carácter almohadilla (#) se usa para indicar que estamos insertando un comentario en el script. Todos los caracteres que aparezcan a la derecha de la almohadilla serán ignorados por el interprete de comandos al ejecutar el script. Veamos un primer ejemplo:

#!/bin/bash
# declaramos la variable CADENA
CADENA="Hola mundo"  # comentario en mitad de una línea
#mostramos la variable por pantalla
echo $CADENA

Guardamos el fichero con el nombre hola_mundo.sh

Para poder ejecutar el script hemos de darle al fichero permiso de ejecución:

$ chmod +x hola_mundo.sh

Ya estamos listos para ejecutar nuestro primer script

$ ./hola_mundo.sh 
 
Hola mundo

Las variables me permiten almacenar valores en memoria y acceder a los mismos por el nombre de la variable.

En el ejemplo anterior utilizamos la variable CADENA. El operador para asignar un valor a la variable es el igual “=”, es lo que hicimos en el script en la linea:

CADENA="Hola mundo!"

Internamente, el sistema reserva una zona de memoria identificado por el valor que está a la izquierda del “=” y almacena en el el valor que está a la derecha del “=”.

A esta operación se le llama inicializar una variable.

Si queremos posteriormente modificar el valor de la variable lo podemos hacer asignándole un nuevo valor:

CADENA="Adios"

Si queremos utilizar la variable dentro del script hacemos la operación de invocarla y, para ello, ponemos su nombre precedido del caracter “$”:

echo $CADENA

El comando echo muestra un valor por pantalla, en este caso, el contenido de la variable $CADENA.

Cuando al invocar una variable la colocamos pegada a un texto el shell no interpreta correctamente la variable. Para establecer claramente el límite de la variable podemos utilizar las llaves {, }

$ var=archivo
$ echo $var1
 
$ echo ${var}1
archivo1

Una variable puede contener caracteres especiales, en particular espacios. El siguiente ejemplo nos dará error:

$ a=hola mundo
mundo: orden no encontrada
$ echo $a

Para lograr que funcione hemos de marcar los caracteres especiales uno por uno o colocar el texto entre comillas dobles o simples. Para el caso anterior cualquiera de las siguiente opciones funcionaría:

$ a=hola\ mundo
$ a="hola mundo"
$ a='hola mundo'

La diferencia principal entre comillas dobles y simples es como son tratadas las variable contenidas dentro de las comillas. En el caso de las comillas dobles las variables son evaluadas, mientras que con las comillas simples no.

$ cat comillas.sh
#!/bin/bash
a=Linux
b=Ubuntu
c="$b es una distribución de $a"
d='$b es una distribución de $a'
 
echo $c
echo $b
 
$ ./comillas.sh
Ubuntu es una distribución de Linux
$b es una distribución de $a

Los parámetros de posición son variables especiales utilizadas cuando se le pasan parámetros a un script

Variable Contenido
$0 Nombre del script
$1-9 $1, $2, $3, …. permite almacenar hasta nueve parámetros posicionales pasados al script
$# Número total de parámetros pasados al script
$* Lista de todos los parámetros

Vamos a verlo con un ejemplo:

$ cat parametros.sh
#!/bin/bash
 
echo "Nombre del script: $0"
echo "Número de parámetros: $#"
echo "Parámetros: primero=$1 segundo=$2 tercero=$3"
echo "Lista de parámetros: $*"
 
$./parametros.sh uno dos tres cuatro
Nombre del script: parametros.sh
Número de parámetros: 4
Parámetros: primero=uno segundo=dos tercero=tres
Lista de parámetros: uno dos tres cuatro

El comando exit permite terminar un script. Por defecto, el valor devuelto es 0 (no error), pero podemos especificar cualquier otro valor entre 0 y 255.

exit 1

El valor de salida se puede recuperar mediante la variable ?

Ejemplo:

$ cat test.sh 
#!/bin/bash
echo "Prueba de exit"
exit 5
 
$ ./test.sh
Prueba de exit
$ echo $?
5

Si queremos que nuestro script interaccione con el usuario pidiéndole valores de teclado para almacenarlos en una variable lo podemos hacer con el comando read de la siguiente forma

echo -n "Introduce un texto:"
read TEXTO
echo "El texto introducido fue: "$TEXTO
  • La opción -n de echo hace que no salte de línea, por lo que el cursos quedará al final de la línea y no en la línea siguiente.
  • read TEXTO se queda a la espera de que introduzcamos un texto (termina cuando pulsamos <enter>) y el valor leído se almacena en la variable TEXTO.
  • En la última línea invocamos la variable y mostramos el texto leído desde el teclado

Si en el ejemplo anterior quisieramos que el nombre del fichero incluyera la fecha en la que se ejecuto la copia, necesitamos obtener, de alguna forma la fecha actual e incluir ese valor en la variable que almacena el nombre del la copia de seguridad. Veamos como hacerlo:

El comando date me da la fecha actual:

$ date
mié ene 18 07:13:25 WET 2012

Además con date puedo obtener la fecha en diferentes formatos:

$ date +%Y%m%d
20120118

Si quisiera que el nombre del fichero fuera copia-seguridad-20120118 debería añadir a copia-seguridad- el resultado del comando anterior. Lo podemos hacer utilizando el operador $() de la siguiente forma:

VARIABLE=$(comando)

Si quiseramos utilizar el valor obtenido

FECHA=$(date +%Y%m%d)
OF=copia-seguridad-${FECHA}.tar.gz

O de una sola vez mediante:

OF=copia-seguridad-$(date +%Y%m%d)

El script quedaría:

#!/bin/bash
OF=copia-seguridad-$(date +%Y%m%d).tar.gz
tar -czf $OF /home/linuxconfig 

También podemos almacenar en una variable o utilizar el resultado de un comando en otro utilizando las comillas invertidas `<comando>` en lugar del operador $(<comando>). Ejemplo:

FECHA=`date +%Y%m%d`
OF=copia-seguridad-$FECHA.tar.gz

Si queremos que nuestro script ejecute diferentes acciones en función del resultado de evaluar una condición lo podemos hacer utilizando las instrucciones if - else. Veamos un ejemplo:

#!/bin/bash
echo -n "Introduce un nombre de directorio: "
read DIRECTORIO
 
# bash check if directory exists
if [ -d $DIRECTORIO ]; then
	echo "El directorio existe"
else 
	echo "El directorio no existe"
fi 

El script lee de teclado la ruta de un directorio y nos informa de si el directorio leído existe o no. ¿Cómo lo hace?:

if evalúa una condición. Las condiciones se hacen poniendo entre corchetes “[” “]” un valor a evaluar. En este caso [ -d ruta_directorio ] devuelve verdadero si el fichero existe.

  • Si la condición es verdadera ejecuta lo que hay a continuación de then.
  • Si la condición es falsa ejecuta lo que hay a continuación del else
  • else es opcional.

Si lo que queremos es comprobar si una condición no se cumple lo que hacemos es poner el operador ! seguido de un espacio antes de los corchetes “[” “]”

# bash check if directory exists
if ! [ -d $DIRECTORIO ]; then
	echo "El directorio no existe"
else 
	echo "El directorio existe"
fi 

Los diferentes tipos de comparaciones que podemos hacer dentro de [ ] son:

Operador		Verdad (TRUE) si:
------------------------------------------
cadena1 = cadena2	cadena1 es igual a cadena2
cadena1 != cadena2	cadena1 no es igual a cadena2
cadena1 < cadena2	cadena1 es menor que cadena2
cadena1 > cadena 2	cadena1 es mayor que cadena 2
-n cadena1		cadena1 no es igual al valor nulo (longitud mayorque 0)
-z cadena1		cadena1 tiene un valor nulo (longitud 0)
Operador		Verdad (TRUE) si:
------------------------------------------
x -lt y			x menor que y
x -le y			x menor o igual que y
x -eq y			x igual que y
x -ge y			x mayor o igual que y
x -gt y			x mayor que y
x -ne y			x no igual que y
Operador		Verdad (TRUE) si:
------------------------------------------
-d fichero		fichero existe y es un directorio
-e fichero		fichero existe
-f fichero		fichero existe y es un fichero regular (no un
			directorio, u otro tipo de fichero especial)

-r fichero		Tienes permiso de lectura en fichero
-s fichero		fichero existe y no esta vacio
-w fichero		Tienes permiso de escritura en fichero
-x fichero		Tienes permiso de ejecucion en fichero (o de busqueda
			si es un directorio)

-O fichero		Eres el dueño del fichero
-G fichero		El grupo del fichero es igual al tuyo.

fichero1 -nt fichero2	fichero1 es mas reciente que fichero2
fichero1 -ot fichero2	fichero1 es mas antiguo que fichero2

Comparación de cadenas

#!/bin/bash
echo -n "Introduce el nombre del usuario"
read USUARIO
if [ $USUARIO = "petete" ]; then
    echo usuario correcto
fi

Comparación numérica

<code bash>
#!/bin/bash
echo -n "Introduce un número"
read NUMERO
if [ $NUMERO -gt 1000 ]; then
    echo el número es mayor de 1000
fi

Comprobación de atributos de fichero

#!/bin/bash
FILE=~/.basrc
if [ -f $FILE ]; then
   echo el fichero $FILE existe
else
   echo fichero no encontrado
fi