Shell scripts
Automatizando comandos de Linux
Este tutorial es la continuación del tutorial sobre la terminal de Linux.
- Comienzo de un script
- Ejecución de scripts
- Variables
- Argumentos de entrada
$1
- Condiciones
if
- Bucles
for
Comienzo de un script
Un script de la shell es un fichero de texto plano compuesto por comandos de terminal que se ejecutan en conjunto automáticamente.
La primera línea indica el tipo de shell que estamos usando. En el caso de usar la shell de Bash, la línea es:
#!/bin/bash
O también, más usado profesionalmente:
#!/usr/bin/env bash
Esta debe ser siempre la primera línea de todo scripts, sin poner saltos de línea ni espacios antes. Recuerda que esta línea debe aparecer siempre en todo script.
Ejecución de scripts
En un script podemos incluir cualquier comando que usemos desde la terminal. Prueba a guardar lo siguiente en un fichero llamado test.sh
:
#!/bin/bash
echo "Este es mi script"
cd ~
ls
Puedes ejecutarlo escribiendo $ bash test.sh
en la terminal.
Otra forma más habitual de ejecutarlo es darle permisos de ejecución primero:
$ chmod u+x test1.sh # Añade permiso de ejecución al usuario
$ ./test.sh # Ejecuta el script
También lo podemos ejecutar con sh
(script genérico) o con bash
(scripts de bash):
$ sh test.sh
$ bash test.sh
La extensión de fichero habitual para scripts es .sh
, pero también es muy frecuente no poner extensión (en nuestro caso el fichero se llamaría simplemente test
).
Comentarios
Cualquier línea que comience por una almohadilla #
es un comentario, y no se ejecuta. Esta es la forma de escribir comentarios que expliquen brevemente lo que hace el código.
También se puede comenzar un comentario a mitad de línea, salvo que esté entre comillas.
#!/bin/bash
# Imprimir la carpeta de usuario
ls ~
# Imprimir procesos
ps -a # -a muestra los de todos los usuarios
echo "Dentro de comillas # no cuenta como comentario"
# El siguiente comando está comentado y no se ejecuta
# cd /
Prevención de errores
En tus scripts incluye siempre tras la primera línea, el comando set -e
. Esto hace que el script no se siga ejecutando si en algún punto encuentra un error. De esta manera evitamos que ese error se pueda propagar generando quizás más errores aún en el resto del script.
#!/bin/bash
set -e
Nosotros obviaremos esta línea el resto del tutorial, pero asegúrate de incluirla siempre.
Variables
Una variable se representa por una palabra que contiene algún dato que podemos usar repetidas veces.
Puedes definir una variable (crearla) que contenga una cadena de texto de la siguiente manera:
nombre_variable="cadena de texto"
Asegúrate siempre de que no existen espacios ni antes ni después del símbolo igual =
.
Esta variable ahora la usamos con el símbolo del dólar $nombre_variable
, también sin espacios.
La ventaja de las variables es que permiten repetir su contenido en múltiples ocasiones en el resto del script. Analiza y prueba el siguiente ejemplo:
#!/bin/bash
nombre_dir="mi-directorio"
echo "Creando el directorio: $nombre_dir"
mkdir $nombre_dir
touch $nombre_dir/fichero.txt
Este script imprime un mensaje por la terminal, crea un directorio, y un fichero dentro de ese directorio. Al tener la variable nombre_dir
, si queremos cambiar ese nombre únicamente deberemos modificar una línea del fichero, sustituyendo "mi-directorio"
por otro nombre.
En un script podemos crear tantas variables como queramos con los nombres que elijamos, siempre que no contengan espacios (podemos usar guiones normales o bajos, ej: mi-variable
, otra_variable
).
Capturar la salida de un comando
Como hemos dicho, en cada línea se ejecuta un comando que podríamos escribir en la terminal, y el resultado se muestra por pantalla. Pero en muchas ocasiones nos interesa capturar este resultado para trabajar con él desde el script, en vez de únicamente mostrarlo al usuario.
Existen varias formas de hacer esto, pero la más común son las tildes graves (no las que usamos normalmente en castellano, sino las que van «hacia atrás»). Prueba lo siguiente:
#!/bin/bash
listado=`ls`
Comprobarás que al ejecutar el script no se muestra nada. Esto es porque el resultado de ls
se ha guardado en la variable listado
, y no hemos hecho nada con ella. Podemos mostrarla con echo
:
#!/bin/bash
listado=`ls`
echo "Contenidos del directorio actual:"
echo "$listado"
Al ejecutarlo, verás que ya se imprime el listado de ficheros. Fíjate en que hemos puesto el echo "$listado"
. Pon siempre comillas dobles de esa manera en echo
, ya que si las quitas cambia su comportamiento y lo imprime en una única línea, lo cual usaremos más adelante.
$ ./mi_listado
Listado del directorio actual:
ciudades
mi_listado
README.md
Recuerda que las variables son muy útiles cuando queremos usarlas varias veces. En este caso, podríamos haber escrito simplemente:
#!/bin/bash
echo "Listado del directorio actual: `ls`"
La captura de comandos es muy común en scripts, y funciona con cualquier comando que puedas escribir en la terminal, incluyendo llamadas a otros scripts.
Dentro de las comillas graves puedes usar cualquier tipo de redirección a fichero o tubería. Analiza el siguiente script:
#!/bin/bash
echo "Este directorio `pwd` tiene `ls | wc -l` elementos."
Pedir datos al usuario
Desde un script podemos solicitar datos al usuario de manera interactiva con el comando read variable
. Esto permite al usuario escribir un texto, y al pulsar la tecla Enter, se guarda ese texto en la variable creada. Prueba a ejecutar lo siguiente:
#!/bin/bash
echo "Dime tu nombre:"
read nombre
echo "Hola, $nombre"
Si lo ejecutamos:
Dime tu nombre:
Mr. Hamster
Hola, Mr. Hamster
Verás que lo que escribe el usuario va en una línea siguiente a la del echo
. Para hacerlo en la misma línea, podemos usar la opción read -p "Texto " variable
(deja un espacio dentro de las comillas para que se vea mejor):
#!/bin/bash
read -p "Dime tu nombre: " nombre
echo "Hola, $nombre"
Si lo ejecutamos esta vez:
Dime tu nombre: Mr. Hamster
Hola, Mr. Hamster
Ejecuta y analiza este otro ejemplo:
#!/bin/bash
read -p "Dime un nombre de usuario: " usuario
echo "Estos son los contenidos de tu carpeta de inicio:"
ls /home/$usuario
Argumentos de entrada $1
Desde el código de un script podemos obtener los argumentos o parámetros que nos pasan desde la consola al ejecutar el script. Estos argumentos los tenemos en las variables $1
, $2
, $3
… Estas variables contendrán el valor que se pase, o estarán en blanco si no se han pasado argumentos.
Por ejemplo, si tenemos el fichero script.sh
:
#!/bin/bash
echo "Primer argumento: $1"
echo "Segundo argumento: $2"
Al ejecutarlo, tendremos:
$ bash script.sh
Primer argumento:
Segundo argumento:
$ bash script.sh hola
Primer argumento: hola
Segundo argumento:
$ bash script.sh hola adios
Primer argumento: hola
Segundo argumento: adios
Es aconsejable pasar estos argumentos a nuevas variables con un nombre más descriptivo:
#!/bin/bash
nombre=$1
apellido=$2
echo "Nombre: $nombre"
echo "Apellido: $apellido"
Condiciones if
Dentro de un script puedes comprobar condiciones del tipo:
si <condición> entonces <haz_esto>
Esto se escribe de la forma:
if [ <condición> ]
then
# Hacer esto
fi
Y también se puede acortar con:
if [ <condición> ]; then
# Hacer esto
fi
Asegúrate de poner siempre espacios antes y después de la condición, o no funcionará como esperas.
La condición para comparar dos cadenas de texto es con el doble igual ==
, por ejemplo:
var="hola"
if [ $var == "hola" ]
then
echo "La variable es hola"
fi
También puedes comprobar que una cadena sea diferente de otra con !=
.
Para comprobar si una variable tiene contenido o si está vacía, se puede usar la opción -z
:
var="" # Sin contenido
if [ -z $var ]
then
echo "La variable está vacía"
fi
Puedes ver todas las opciones que se pueden usar con man test
.
Comprobaciones sobre archivos y directorios
También se pueden hacer comprobaciones sobre si ficheros o directorios existen:
read -p "Dime un fichero: " fichero
if [ -a $fichero ]
then
echo "El fichero existe"
fi
Se puede hacer una comprobación opuesta añadiendo !
antes de la opción (separada por espacio):
read -p "Dime un fichero: " fichero
if [ ! -a $fichero ]
then
echo "El fichero no existe"
fi
Esta tabla resume algunas comprobaciones sobre ficheros:
-e |
¿Existe? (fichero, directorio, enlace…) |
-d |
¿Es un directorio? |
-f |
¿Es un fichero? |
-r |
¿Tiene permisos de lectura? |
-w |
¿Tiene permisos de escritura? |
-x |
¿Tiene permisos de ejecución? |
También puedes añadir la palabra else
para realizar comprobaciones del tipo
si <condición> entonces <haz_esto> si no <haz_esto_otro>
if [ <condición> ]
then
# Hacer esto
else
# Hacer esto otro
fi
Este ejemplo es una versión más completa de otro visto previamente:
read -p "Dime un nombre de usuario: " usuario
if [ -d /home/$usuario ]
then
echo "Estos son los contenidos de tu carpeta de inicio:"
ls /home/$usuario
else
echo "Ese usuario no tiene carpeta de inicio"
fi
Bucles for
Prueba el siguiente código con un bucle for
:
#!/bin/bash
for variable in 1 2 3 4 5
do
echo "Imprimiento $variable"
done
Todas las líneas de código entre do
y done
se repiten varias veces, y lo único que cambia es el contenido de la variable que crea el bucle for
. Este script imprimirá:
$ ./script.sh
Imprimiento 1
Imprimiento 2
Imprimiento 3
Imprimiento 4
Imprimiento 5
Podemos usar este bucle para recorrer las líneas de un fichero de la siguiente manera:
#!/bin/bash
for linea in `cat file.txt`
do
echo "Línea: $linea"
done