Вы находитесь на странице: 1из 20

CAPÍTULO 15

SHELL BASH SCRIPTING

Introducción y objetivos de aprendizaje

Anteriormente en este curso, aprendimos cómo se pueden tomar varios comandos y


transformarlos en comandos potentes mediante canalizaciones.
En esta lección, vamos a hablar acerca de los scripts, con las cuales podemos
encomendarle al sistema una serie de acciones que debe realizar, estas se pueden
reutilizar en el futuro y automatizar muchas tareas.
En este módulo, vamos a hablar acerca de las características y las capacidades de varios
shells, hablaremos de la sintaxis del shell, hablaremos acerca de las variables de entorno
y cómo pasar argumentos desde el exterior, y también hablaremos acerca de expresiones
aritméticas.
¡Comencemos!

Objetivos de aprendizaje
Al final de este capítulo, debes ser capaz de:
 Explicar las características y capacidades del bash Shell
scripting.
 Conocer la sintaxis básica de las declaraciones y secuencias
de comandos.
 Estar familiarizado con los distintos métodos y
construcciones.
 Saber cómo probar la existencia y propiedades de archivos
y otros objetos.
 Usar sentencias condicionales, tal como
bloques if-then-else
 Realizar operaciones aritméticas usando lenguaje de scripting.

Sección 1: Características y capacidades

Introducción a scripts
Supongamos que deseamos
buscar un archivo, debemos
comprobar si el archivo existe
y, a continuación, responder
en consecuencia, mostrando
un mensaje para confirmar o
no confirmar la existencia del
archivo. Si sólo tenemos que
hacerlo una vez, podemos
simplemente escribir una
secuencia de comandos en el
terminal. Sin embargo, si necesitamos hacer esta operación varias veces, el camino a
seguir es la automatización. Con el fin de automatizar los conjuntos de comandos
necesitaremos aprender cómo escribir shell scripts, de los cuales los más comunes son
utilizados con bash. El gráfico ilustra algunos de los beneficios de la implementación de
scripts.

Introducción a los scripts de shell.


Recordemos nuestra discusión anterior, un shell es un intérprete de línea de comandos
que provee como interfaz de usuario la ventana del terminal. También se puede utilizar
para ejecutar scripts, incluso en sesiones no interactivas sin una ventana de terminal,
como si los comandos se escribieran directamente.
Por ejemplo , escribir find . -name "*.c" -ls en la línea de comandos realiza lo mismo
que ejecutar un archivo de comandos que contiene las líneas:
#!/bin/bash
find . -name "*.c" -ls
El #!/bin/bash de la primera línea debe ser reconocido por cualquiera que haya
desarrollado algún tipo de script en entornos UNIX. La primera línea del script, que
empieza con #!, contiene la ruta de acceso completa del intérprete de comandos (en este
caso /bin/bash) que va a ser usado en el archivo. Como veremos en la siguiente pantalla,
tenemos varias opciones, dependiendo del lenguaje que utilicemos.

Opciones de comandos de shell


El intérprete de comandos se encarga de la
ejecución de las sentencias que siguen en el
script. Los intérpretes usados comúnmente
incluyen: /usr/bin/perl, /bin/bash, /bin/csh,
/usr/bin/python y /bin/sh.
Escribir una secuencia de comandos larga en una
ventana de terminal puede ser complicado,
laborioso, propenso a errores y consume su tiempo. Mediante la implementación de shell
scripts, utilizando la línea de comandos se convierte en una manera eficiente y rápida para
lanzar secuencias complejas de pasos. El hecho de que las shell scripts son guardadas en
un archivo también facilita el uso de ellos para crear nuevas variaciones del script y
compartir los procedimientos estándar con varios usuarios.
Linux proporciona una gran variedad de shells; lo que está disponible en el sistema está
listado exactamente en /etc/shells. Las opciones típicas son:
/bin/sh
/bin/bash
/bin/tcsh
/bin/csh
/bin/ksh
La mayoría de los usuarios de Linux utilizan por defecto el shell bash, pero aquellos con
largos antecedentes con otros shells de UNIX pueden querer cambiar el valor
predeterminado.
Podemos descargar UNIX Shell.pdf en el vínculo:
https://courses.edx.org/asset-v1:LinuxFoundationX+LFS101x.2+1T2015+type@asset+block/Chap14_UNIXShell.pdf

y para leer más sobre los shell de UNIX.

bash scripts
Vamos a escribir un simple bash script que muestra un mensaje de dos líneas en la
pantalla. Escribimos:
$ cat > exscript.sh
#!/bin/bash
echo "Hola"
echo "Mundo"
Y pulsamos Enter y Ctrl-D para guardar el archivo, o simplemente crear exscript.sh en
nuestro editor de texto favorito. A continuación, escribimos chmod +x exscript.sh para
hacer que el archivo sea ejecutable. (El comando chmod +x hace que el archivo sea
ejecutable para todos los usuarios). A continuación, podemos ejecutarlo escribiendo
simplemente ./exscript.sh o haciendo:
$ bash exscript.sh
Hola
Mundo
Nota: si utilizamos la segunda forma, no tenemos que hacer el archivo ejecutable.
Ejemplo interactivo usando bash scripts
Ahora, vamos a ver cómo crear un ejemplo más interactivo utilizando un bash script. Se
pedirá al usuario que introduzca un valor, que será visualizado en la pantalla. El valor se
almacena en una variable temporal, sname. Podemos hacer referencia al valor de una
variable de shell colocando un $ delante del nombre de la variable, como $sname. Para
crear este script, necesitamos crear un archivo llamado ioscript.sh en su editor favorito
con el siguiente contenido:
#!/bin/bash
# lectura interactiva de variables
echo "Introduce tu nombre"
read sname
# Muestra los valores de las variables
echo $sname
Una vez más, lo hacemos ejecutable con chmod +x ioscript.sh
En el ejemplo anterior, cuando el script ./ioscript.sh se ejecuta, el usuario recibirá un
mensaje INTRODUZCA SU NOMBRE. A continuación, el usuario debe introducir un valor y
pulse la tecla Enter. El valor será impreso en pantalla.
Nota adicional: El hash-tag/pound-sign/number-sign (#) se utiliza para iniciar los
comentarios en la secuencia de comandos y puede colocarse en cualquier lugar de la línea
(el resto de la línea es considerado un comentario)

Valores de retorno
Todos los scripts de shell
generan un valor de
retorno tras la finalización de
su ejecución; el valor se puede
ver con la instrucción exit. El
retorno de valores permite a un
proceso supervisar el estado de salida de otro proceso, a menudo de una relación
padre-hijo. Esto ayuda a determinar cómo ha terminado este proceso y tomar las medidas
necesarias adecuadas, dependerá del éxito o el fracaso.
Visualización de los valores de retorno
Mientras se ejecuta un script, podemos buscar un valor específico o condición y obtener
un resultado exitoso o no. Por convención, un éxito se devuelve como 0, y un fracaso
como un valor distinto de cero. Una manera fácil de demostrar una finalización exitosa o
no es ejecutar ls en un archivo que exista y otro que no, como se muestra en el ejemplo
siguiente, donde el valor de retorno se almacena en una variable de entorno representada
por $?:
$ ls /etc/passwd
/etc/passwd
$ echo $?
0
En este ejemplo, el sistema es capaz de localizar el archivo /etc/passwd y devuelve un
valor de 0 para indicar el éxito; el valor de retorno se almacena siempre en la variable de
entorno $?. A menudo, las aplicaciones traducen estos valores de retorno en un mensaje
significativo fácilmente comprensible por el usuario.

Sección 2: Sintaxis

Sintaxis básica y caracteres especiale


Los scripts requieren que sigamos una sintaxis de lenguaje estándar. Una serie de reglas
delinean cómo definir variables y cómo construir y dar el formato permitido a
declaraciones, etc. La tabla enumera algunos caracteres especiales usados dentro de bash
scripts:

Caracter Descripción

# Se utiliza para añadir un comentario, excepto cuando se usa \#


ó #! para iniciar una script
\ Se utiliza al final de una línea para indicar que continua en la
siguiente línea

; Se utiliza para interpretar lo que sigue como un nuevo comando

$ Se utiliza para indicar que lo que sigue es una variable

Tenga en cuenta que cuando se inserta # al principio de una línea de comentario, la línea
entera es ignorada.
# Esta línea no se ejecutará

División comandos largos en varias líneas


Los usuarios a veces necesitan combinar varios comandos y declaraciones e incluso
ejecutar sentencias
condicionalmente basado en
el comportamiento de los
operadores utilizados entre ellos.
Este método es llamado
encadenamiento de comandos
(chaining of commands).
El operador de concatenación
(\) se utiliza para concatenar comandos largos en varias líneas en el shell.
Por ejemplo, si queremos copiar el
archivo /var/ftp/pub/userdata/cusdata/read desde el directorio server1.linux.com
al directorio /opt/oradba/master/abc en server3.linux.co.in. Para realizar esta
acción, podemos escribir el comando utilizando el operador \ de esta forma:
scp abc@server1.linux.com:\
/var/ftp/pub/userdata/custdata/read \
abc@server3.linux.co.in:\
/opt/oradba/master/abc/
El comando se divide en varias líneas para hacerlo más legible y fácil de entender. El
operador \ al final de cada línea combina los comandos de varias líneas y lo ejecuta como
un único comando.

Poniendo varios comandos en una sola línea


A veces puede que querramos agrupar varios comandos en una sola línea. El carácter ;
(punto y coma) se utiliza para separar
estos comandos y ejecutarlos
secuencialmente como si se hubieran
escrito en líneas separadas.
Los tres comandos en el siguiente
ejemplo se ejecutan incluso si falla alguno de los anteriores:
$ make ; make install ; make clean
Sin embargo, es posible que querramos anular los comandos subsiguientes si uno falla.
Podemos hacer esto utilizando el operador && (and) como en:
$ make && make install && make clean
Si el primer comando falla, el segundo no se ejecutará nunca. Un refinamiento final es
utilizar el operador || (or) como en el siguiente ejemplo:
$ cat file1 || cat file2 || cat file3
En este caso, continúa hasta que algo sucede y luego se detiene ejecutando algunos pasos
adicionales.

Funciones
Una función es un bloque de código que implementa un conjunto de operaciones. Las
funciones son útiles para ejecutar procedimientos muchas veces incluso con diferentes
variables de entrada. Las funciones se suelen denominar también subrutinas. El uso de
funciones en scripts requieren de dos pasos:
1. Declarar la función
2. Llamar a la función
La declaración de la función requiere un nombre que se utiliza para invocarla. La sintaxis
correcta es:

function name () {
command...
}
Por ejemplo, la siguiente función se denomina display:
display () {
echo "Este es un ejemplo de función"
}

La función puede ser tan larga como queramos y pueden tener muchas instrucciones o
declaraciones. Una vez definida la función puede llamarse posteriormente tantas veces
como sea necesario. En el ejemplo que se muestra en la figura siguiente, se puede
observar un refinamiento de uso frecuente: el pasaje de argumentos a la función. El
primer argumento es referido como $1, el segundo como $2, etc.

Los comandos del shell integrado

Los Shell scripts se utilizan para ejecutar secuencias de comandos y otros tipos de
instrucciones.

Los comandos pueden dividirse en las siguientes categorías:


 Aplicaciones compiladas
 Comandos integrados del bash
 Otros scripts
Las aplicaciones compiladas son archivos
ejecutables binarios que se pueden
encontrar en el sistema de archivos. Los
script del shell siempre tiene acceso a
aplicaciones compiladas tales como
rm, ls df, vi, y gzip.
bash tiene muchos comandos
integrados (built-in commands) que sólo
pueden utilizarse para mostrar la salida
en una terminal shell o una shell script.
A veces estos comandos tienen el mismo
nombre que programas ejecutables del
sistema como, por ejemplo, echo, que
puede conducir a problemas sutiles. Los
comandos bash integrados incluyen cd,
pwd, echo, read, logout, printf, let y ulimit.
Una lista completa de comandos bash integrados puede encontrarse en la página man de
bash, o simplemente escribiendo help.

Sustitución de comandos
En ocasiones, puede ser necesario sustituir el resultado de un comando como una parte
de otro comando. Puede hacerse de dos maneras:
 Encerrando la orden interna con las comillas invertidas (`).
 Encerrando la orden interna en $( )
No importa el método, el comando se ejecutará en un entorno de shell nuevo, y la salida
estándar del shell se insertará donde se indicó la sustitución de comandos.
Prácticamente cualquier comando se puede ejecutar de esta manera. Ambos métodos
permiten la sustitución de comandos; sin embargo, el método $( ) permite el
anidamiento de comandos. Los nuevos scripts deberían utilizar siempre este método más
moderno. Por ejemplo:
$ cd /lib/modules/$(uname -r)/
En el ejemplo anterior, la salida del comando "uname -r" se convierte en el argumento
para el comando cd.
Variables de entorno
Casi todos los scripts utilizan variables que contienen un valor, que puede ser utilizado
en cualquier parte del script. Estas variables pueden ser definidas por el usuario o por el
sistema. Muchas aplicaciones utilizan estas variables de entorno (ya cubiertas en el
capítulo "Entorno de usuario") para alimentar entradas, validación y control del
funcionamiento.
Algunos ejemplos de variables de entorno estándar son HOME, PATH y HOST. Cuando se hace
referencia a las variables de entorno, deben ser precedidas por el símbolo $ como
en $HOME. Podemos ver y ajustar el valor de las variables de entorno. Por ejemplo, el
siguiente comando muestra el valor almacenado en la variable $PATH:
$ echo $PATH
Sin embargo, no es necesario el prefijo cuando ajustamos o modificamos el valor de la
variable. Por ejemplo, el siguiente comando establece el valor de la variable MYCOLOR a
azul:
$ MYCOLOR=blue
Podemos obtener una lista de las variables de entorno con los comandos env, set
o printenv.
Exportar Variables
De forma predeterminada, las variables creadas dentro de un script sólo están disponibles
para los siguientes pasos de la script. Todos los procesos hijos (sub-shells) no tienen
acceso automático a los valores de estas variables. Para ponerlas a disposición de los
procesos hijo, deben ser realizado usando la instrucción export como en:

export VAR=value

VAR=value ; export VAR


Mientras que los procesos hijo quedan autorizados a modificar el valor de las variables
exportadas, el proceso padre no verá ningún cambio; las variables exportadas no son
compartidas, sólo se copian.

Los parámetros de un script


A menudo los usuarios necesitan pasar valores de parámetros a un script, como un
nombre de archivo, fecha, etc. Las scripts tomarán caminos diferentes o llegarán a
resultados diferentes según los parámetros (argumentos) que se pasan a los comandos.
Estos valores pueden ser texto o números, como en:
$ ./script.sh /tmp
$ ./script.sh 100 200

Dentro de un script, el parámetro o argumento está representado con un $ y un


número. La tabla siguiente enumera algunos de estos parámetros.

Parámetro Significado

$0 Nombre del script

$1 Primer parámetro
$2, $3, etc. Segundo, tercer parámetro, etc.

$* Todos los parámetros

$# Número de argumentos

Utilizando los parámetros de script


Usando su editor de texto favorito, cree un nuevo script llamado script3.sh con el
siguiente contenido:
#!/bin/bash
echo "El nombre de este programa es: $0"
echo "El primer argumento que se pasa desde la línea de comandos es: $1"
echo "El segundo argumento que se pasa desde la línea de comandos es: $2"
echo "El tercer argumento que se pasa desde la línea de comandos es: $3"
echo "Todos los argumentos que se pasan en la línea de comandos son: $*"
echo
echo "Tarea realizada con $0"
Hagamos el script ejecutable con chmod +x. Ejecutemos el script dándole tres
argumentos como en: script3.sh uno dos tres, y el script se procesa de la siguiente
manera:

$0 imprime el nombre de script: script3.sh


$1 imprime el primer parámetro: uno
$2 imprime el segundo parámetro: dos
$3 imprime el tercer parámetro: tres
$* imprime todos los parámetros: uno dos tres
La declaración final se convierte en: Tarea realizada con script3.sh

Redirección de la salida
La mayoría de los sistemas operativos aceptan la entrada desde el teclado y muestran la
salida en pantalla de la terminal. Sin embargo, con las script del shell podemos enviar la
salida a un archivo. El proceso de desviar la salida a un archivo se denomina redirección
de la salida.
El carácter > es usado para escribir la salida a un archivo. Por ejemplo, el siguiente
comando envía la salida de free en el archivo /tmp/free.out:

$ free > /tmp/free.out


Para comprobar el contenido de /tmp/free.out, en el símbolo del sistema, escribimos
cat /tmp/free.out
Se anexan dos > caracteres (>>) a la salida de un archivo si este existe, y actúa como > si
el archivo no existe.

Redirección de entrada
De la misma forma que la salida puede redirigirse a un archivo, la entrada de un comando
se puede leer desde un archivo. El proceso de leer la entrada desde un archivo se
denomina redirección de entrada y utiliza el carácter < . Si creamos un archivo llamado
script8.sh con el siguiente contenido:
#!/bin/bash
echo "Line count"
wc -l < /temp/free.out
y, a continuación, lo ejecutamos con chmod +x script8.sh ; ./script8.sh, contará el
número de líneas del archivo /temp/free.out y mostrará los resultados.
Sección 3: Construcciones

La instrucción if
Se utiliza la instrucción if para la toma de decisiones
condicionales, es una estructura básica que cualquier
lenguaje de programación o secuencia de comandos
útiles debe tener.
Cuando se usa una instrucción if, las subsiguientes
acciones dependen de la evaluación de determinadas
condiciones, tales como:
 Comparaciones numéricas o de cadena
 Valor de retorno de un comando (0 si fue exitoso)
 Existencia de un archivo o permisos
En forma compacta, la sintaxis de una instrucción if es:
if TEST-COMMANDS; then CONSEQUENT-COMMANDS; fi
Una definición más general es:
if condition
then
stetements
else
statements
fi

Ejemplo:
Sentencias if anidadas
La instrucción elif

Usando la instrucción if
La siguiente instrucción if comprueba si existe el archivo /etc/passwd y, si se encuentra
el archivo muestra el mensaje /etc/passwd exists.:
if [ -f /etc/passwd ]
then
echo "/etc/passwd exists."
fi
Observemos el uso de los corchetes ([]) para delinear la condición de prueba. Hay
muchos otros tipos de pruebas que podemos realizar, como, por ejemplo, comprobar si
dos números son iguales, mayores o menores el uno que el otro y tomar una decisión en
consecuencia; discutiremos estas otras pruebas.
En scripts modernos podemos ver corchetes dobles como en [[ -f /etc/passwd ]]. Esto
no es un error. Nunca es erróneo hacerlo y evita algunos problemas sutiles como referirse
a una variable de entorno vacía sin encerrarla entre comillas dobles; no vamos a hablar de
esto aquí.

Pruebas de archivos
Podemos utilizar la instrucción if para comprobar los atributos de un archivo como:
 Existencia de archivo o directorio
 Permiso de lectura o escritura
 Permiso de ejecución.
Por ejemplo, en el ejemplo siguiente:
if [ -f /etc/passwd ] ; then
ACTION
fi
La instrucción if comprueba si el archivo /etc/passwd es un archivo regular.
Notemos que es muy común poner "; then" en la misma línea que la instrucción if.
bash proporciona un conjunto de condicionales de archivo, que se pueden usar con
la instrucción if, entre ellos:

Condición Significado

-e archivo Comprueba si el archivo existe.

-d archivo Comprueba si el archivo es un directorio.

-f archivo Comprueba si el archivo es un archivo regular (es


decir, no es un enlace simbólico, nodo de dispositivo,
directorio, etc.).
-s archivo Comprueba si el archivo tiene tamaño distinto de cero.

-g archivo Comprueba si el archivo tiene sgid establecido en 1.

-u archivo Comprueba si el archivo tiene suid establecido en 1.

-r archivo Compruebe si el archivo es legible.

-w archivo Verifica si se puede escribir en el archivo.

-x archivo Comprueba si el archivo es ejecutable.

Podenis ver la lista completa de condiciones utilizando el comando man 1 test.

Ejemplo de Prueba de cadenas


Podemos utilizar la instrucción if para comparar cadenas utilizando el operador == (dos
signos igual). La sintaxis es como sigue:
if [string1 = string2 ] ; then
ACTION
fi
Ahora vamos a examinar un ejemplo de prueba de cadenas.
En el ejemplo ilustrado aquí, la instrucción if se utiliza para comparar la entrada
proporcionada por el usuario y, como consecuencia, mostrar el resultado.

Test numéricos
Podemos utilizar los operadores definidos específicamente con la instrucción if para
comparar números. En la siguiente tabla se enumeran los distintos operadores que están
disponibles.

Operador Significado

-eq Igual a
-ne No es igual a

-gt Mayor que

-lt Menos de

-ge Mayor que o igual a

-le Menor o igual a

La sintaxis para la comparación de números es la siguiente:


exp1 -op exp2

Ejemplo de pruebas para los números


Veamos ahora un ejemplo de comparar números mediante los diversos operadores:

Pruebas de números (vídeo)


Expresiones aritméticas
Las expresiones aritméticas pueden ser evaluadas en las siguientes tres maneras (los
espacios son importantes!):
 Usando la utilidad expr: expr es un programa estándar pero algo obsoleto. La
sintaxis es como sigue:
expr 8 + 8
echo $(expr 8 + 8)
 Utilizando $((...)) Sintaxis: Este es la formato shell incorporado. La sintaxis es como
sigue:
echo $((x+1))
 Utilizar el comando Shell incorporado let. La sintaxis es como sigue:

let x=( 1 + 2 ); echo $x


En scripts de shell moderno el uso de expr es mejor reemplazarla con var=$((...))
Sumario

Has completado este capítulo. Resumamos los conceptos


clave cubiertos:
 Los scripts son una secuencia de instrucciones y
comandos almacenados en un archivo que puede ser
ejecutada por una shell. El shell más comúnmente
usado en Linux es bash.
 La sustitución de comandos nos permite sustituir el
resultado de un comando como una parte de otro
comando.
 Funciones o rutinas son un grupo de comandos que se
utilizan para la ejecución.
 Las variables del entorno tiene valores pre-asignados por el shell o definidas y
modificadas por el usuario.
 Para hacer las variables de entorno visibles a los procesos hijo, necesitan ser
exportadas.
 Los scripts pueden comportarse de forma diferente en función de los parámetros
(valores) que se le pasan a ellos.
 El proceso de escribir la salida en un archivo se denomina redirección de la salida.
 El proceso de leer la entrada desde un archivo se denomina redirección de entrada.
 La instrucción if se utiliza para seleccionar una acción basada en una condición.
 Las expresiones aritméticas consisten de números y operadores aritméticos, tales
como +, - y *.