Aso Ud01 Scripting Con Bash Alum
Aso Ud01 Scripting Con Bash Alum
Aso Ud01 Scripting Con Bash Alum
$mkdir bin
$cat.profile
ANTONIO J. LEÓN DELGADO
1
UD 01: Scripting con bash
Probar ahora el echo $path y ver si esta /home/raul/bin (reiniciar)
Le damos permisos
$sudo chmod 755 cls.sh
$cls.sh
$ls -l
¿Qué es /bin/sh?
Es un ejecutable que representa el shell del sistema
Enlace simbolico a dash, ,es decir, si ejecutamos sh, realmente estamos
ejecutando dash
A este le llamamos subshell o shell hijo, que puede ser del mismo tipo o de uno
diferente disponible en el sistema. Para iniciar un subshell sencillamente tenemos que
escribir el nombre del programa (sh, bash, csh, ksh, etc.) en la línea de comandos y
pulsar la tecla de retorno. Si hemos cambiado de shell, en general, aparecerá un
indicador de línea de comandos diferente, ya que cada shell tiene una apariencia
diferente. Podemos finalizar la ejecución del subshell y devolver al shell padre
escribiendo la orden exit.
($ file Escritorio/scripssts/grep_raul.sh)
El shell Bash
El shell Bash es el shell predeterminado de casi todas las distribuciones
GNU/Linux, así como de Mac OS X, y puede ejecutarse en la mayoría de los sistemas
operativos tipo Unix. También se ha llevado a Microsoft Windows para el proyecto
Cygwin.
El nombre Bash
Es un acrónimo de Bourne-Again Shell (“otro shell Bourne"), haciendo un juego
de palabras (born-again significa "renacimiento") sobre el shell Bourne (sh), que fue
uno de los primeros intérpretes importantes de Unix.
El Bash es un intérprete de comandos compatible con el shell Bourne (sh), que
incorpora características útiles del shell Korn (ksh) y del shell C (csh), con el objetivo de
cumplir con el estándar POSIX. Bash ofrece mejoras funcionales sobre sh tanto para la
programación como para el uso interactivo y se ha convertido en el estándar de facto
para la programación de guiones de shell.
Observación: como el shell Bash (bash) es compatible con el shell Bourne (sh),
las órdenes y los programas escritos para sh pueden ser ejecutados con bash sin
modificación, pero lo contrario no siempre es cierto.
Abrir una sesión con Bash
Cuando arranca, el sistema presenta a los usuarios una interfaz determinada
que pu ede ser de texto o gráfica, dependiendo de los sistemas operativos o de cómo
esté configurado el modo de arranque.
La interacción con Bash se hace a través de un emulador de terminal. Si hemos
iniciado sesión al sistema en modo consola (texto), una vez validados obtendremos el
ANTONIO J. LEÓN DELGADO
5
UD 01: Scripting con bash
acceso directo a un shell. Si hemos iniciado sesión en modo gráfico, tendremos que
ejecutar alguno de los programas de emulación de terminal disponibles. La mayoría
de los sistemas Unix disponen de una aplicación de terminal accesible por alguna de
las opciones del menú principal, por ejemplo, la distribución de Linux Debian, por
ejemplo, Ubuntu, accedemos a un terminal desde
Aplicaciones > Accesorios > Terminal (depende de la versión y el escritorio
instalado).
Interpretación de órdenes
La función principal del shell es interpretar órdenes, ya sea las órdenes escritas
de manera interactiva en la interfaz de la línea de comandos que proporciona, o las
órdenes escritas en un archivo de texto (guion de shell).
Las órdenes que escribimos, ya sea en el indicador de la línea de comandos
del shell o en un programa de shell (por ejemplo, terminator), tienen el siguiente
formato:
nom_orden [ -opciones ] [ argumentos ] <INTRO>, donde:
nom_orden: es el nombre de la orden que queremos ejecutar.
opciones: las órdenes pueden o no llevar opciones. Normalmente las opciones
se escriben con un guion delante o con doble guion seguido de una palabra.
argumentos: dependiendo de la orden, se pueden poner argumentos que
muchas veces representan una cadena de caracteres, el nombre de un archivo o
directorio.
El shell interpreta siempre el espacio en blanco como separador de órdenes,
opciones o argumentos. Si no ponemos los espacios correctamente, obtendremos un
mensaje de error.
Ejercicio 1º
Ejemplos de generación de nombres de ficheros con expresiones regulares
Sitúate en el directorio /usr/bin:
Lista los nombres de archivos y directorios que empiecen por c:
LS
Find
FIND
FIND
FIND
3º Mostrar todos los nombres de ficheros que tengan una extensión compuesta de
un solo carácter
4º Mostrar todos los nombres de ficheros cuyo nombre empiece por f u o y termine
con el carácter . Seguido de un minúscula
5º Mostrar todos los nombres de ficheros cuyo nombre tiene en el 2º carácter una
mayúscula, un dígito o la letra i. A continuación, puede ir una cadena cualquiera,
incluso nada.
Tenemos estas:
¿(expresion)
La expresion estara presente 0 o 1 veces
*(expresion)
La expresion estara presente 0 o n veces
+(expresion)
La expresion estara presente 1 o n veces
@(expresion)
La expresion estara presente solo 1 vez
!(expresion)
La expresion o estara presente
Alternativas
Una barra vertical en el interuir de una expresion compleja significa “o bien”.
?(expresion|expresion|...)
*(expresion|expresion|...)
+(expresion|expresion|...)
@(expresion|expresion|...)
!(expresion|expresion|...)
Observación: ten en cuenta que no hay ningún espacio antes ni después del
signo igual. Si se pone algún obtendremos un error.
Los siguientes son ejemplos válidos de definición de variables:
NOMBRE=Marco
APELLIDOS ="Ros Rojo"
EDAD=31
El valor asignado a la variable APELLIDOS la hemos cerrado entre comillas
dobles para que el shell no interprete el espacio que hay entre los dos apellidos. Para
evitar la posibilidad de cometer errores, podemos optar por poner el valor siempre
entre comillas dobles:
variable = "valor"
El valor de la variable siempre lo podemos cambiar asignándole otro valor (es
decir, es como si eliminamos la variable y la volvemos a crear con un nuevo valor). Por
ejemplo:
NOMBRE=mia
El valor asociado a una variable puede ser utilizado mediante el nombre de la
variable precedido con el símbolo dólar: $variable.
Este mecanismo se llama sustitución de variables.
El shell realiza la sustitución de variables a cualquier línea de comandos que
contenga un símbolo $ seguido de un nombre de variable válido.
Podemos visualizar el valor de una variable definida con el orden echo y
utilizando el mecanismo de sustitución de variables:
echo $variable
Por ejemplo:
echo $APELLIDOS
Después de ejecutar la orden anterior, el valor asociado a la variable llamada
APELLIDOS se muestra por pantalla.
En la sustitución de variables se puede hacer uso de llaves para delimitar el
nombre de la variable: ${variable}. La utilización de llaves nos permite, por ejemplo,
hacer la sustitución de la variable seguida de un texto. Por ejemplo:
PREFIJO=extra
echo ${PREFIJO}ordinario
La orden anterior muestra por pantalla la palabra "extraordinario". Haciendo
uso de la misma variable PREFIJO podemos escribir la siguiente orden:
echo "Palabras que empiezan por $PREFIJO: ${PREFIJO}ordinario, ${PREFIJO}polar”
La orden anterior muestra por pantalla la frase "Palabras que empiezan por
extra: extraordinario, extrapolar".
Ejecución de uno.sh
El shell hijo no conoce la variable x del shell padre ni el shell padre conoce la
variable x del shell hijo.
Ejecución de uno.sh
Ahora, el shell hijo conoce la variable x del shell padre (por el export) pero el
padre no conoce la variable del shell hijo.
Ejecuto uno.sh
Observación: localización
Expansión aritmética
El mecanismo de expansión aritmética del Bash permite la evaluación de una
expresión aritmética y la sustitución del resultado.
El formato para hacer la expansión aritmética es:
$((expresión_aritmética))
Esta técnica anula el significado de todos los caracteres especiales que estén
dentro de las comillas simples.
Filtros y 'pipelines'
En Unix hay unas órdenes que se utilizan mucho en las pipelines y que
llamamos filtros.
Los filtros son órdenes que aceptan datos de la entrada estándar, escriben la
salida a la salida estándar y escriben los errores en la salida estándar de errores, y
nunca modifican los datos de entrada. Debido a su funcionamiento, es frecuente
utilizar filtros en las pipelines. Por ejemplo, un filtro muy utilizado es sort, que sirve
Nombres de ficheros
Recuerda: las órdenes which, whereis y locate nos sirven para verificar si ya
existen archivos con un nombre determinado. Otras órdenes de búsqueda: apropos y
whatis
Para empezar, abre un editor de texto y crea un nuevo archivo que contenga
las cuatro líneas siguientes:
#!/bin/bash
# Ejemplo de shell básico
echo "Hola, mundo"
echo "Soy $USER "
Aunque ahora no queremos analizar a fondo el significado de cada una de las líneas
anteriores, hacemos una descripción breve para saber qué hace el guion:
1.- La primera línea indica al sistema que el programa Bash ubicado en el
directorio /bin debe ejecutar el resto de instrucciones que hay en el script.
2.- La línea siguiente es un comentario y, por tanto, el shell la ignora.
3.- La tercera línea es una orden echo, que permite mostrar texto por pantalla,
en este caso, la frase "Hola, mundo".
4.- La última línea es otra orden echo que muestra por pantalla el mensaje “Soy
$USER” sustituyendo el valor de la variable USER por el nombre del usuario que
ejecuta el guion.
Una vez hemos escrito las líneas sin errores, guardamos el archivo y le damos
un nombre para poder ejecutarlo desde la línea de comandos.
Variable PATH
La variable PATH contiene la lista de directorios donde el shell se dirigirá para
localizar las órdenes que ejecutamos. Esto nos permite escribir las órdenes
escribiendo sólo su nombre y sin especificar el directorio donde están situadas, es
decir, sin preocuparnos de dónde se encuentran en el disco. La búsqueda de la orden
solicitada en los directorios que se especifican en la variable PATH se hace de
izquierda a derecha. Si no encuentra el orden en ninguno de los directorios
especificados en la variable PATH, el shell avisa con un mensaje de error que no se ha
encontrado la orden. Puedes ver el valor de la variable PATH con la orden:
$echo $PATH.
Cuando el bash ejecuta un shell script, crea un proceso hijo que ejecuta otro
bash, el cual lee las líneas del archivo, las interpreta y ejecuta como si vinieran del
ANTONIO J. LEÓN DELGADO
33
UD 01: Scripting con bash
teclado. El proceso bash padre espera mientras el bash hijo ejecuta el script hasta el
final, y en ese momento el control vuelve al proceso padre, el cual vuelve a poner el
indicador o prompt. Los cambios en el entorno de un shell hijo no afectan al entorno
del shell padre.
Por lo tanto, si en el guion hay órdenes que modifican el entorno, tales como
cambiar de directorio actual, modificar el valor de una variable de entorno, crear una
nueva variable, etc., estos cambios sólo tienen efecto en el entorno del shell hijo y
desaparecen una vez finaliza la ejecución del guion.
Si queremos ejecutar un guion en el shell actual en lugar de con un shell hijo y,
por tanto, modificar el entorno actual, debemos ejecutar el guion con la orden source.
source nombre_script # Ejecutar en el shell actual
Script
else
if [ $X -gt 10 ] ; then
echo “$X es mayor que 10"
else
echo “$X es igual a 10"
fi
fi
La tabulación nos permite leer el código y seguir la lógica del programa con más
comodidad, así como evitar errores de programación (olvidar una palabra clave de
cierre de una estructura de control, situar una palabra clave en algún lugar indebido,
etc.).
No hay ninguna norma que fije cómo se debe tabular el código; hay quien
utiliza tabuladores de dos espacios y quien prefiere cuatro espacios. Lo que importa es
utilizar un estilo homogéneo a lo largo de todo el shell script.
Si usamos un editor de texto plano, debemos sangrar el código a mano, o bien
con espacios o bien con tabuladores. Algunos editores avanzados nos facilitan este
trabajo haciendo que a medida que escribimos el código se vaya “sangrando” de
manera automática sin que nosotros nos tengamos que preocupar de las tabulaciones.
Podemos añadir la opción -v para mostrar todas las líneas de entrada al shell,
incluyendo comentarios, a medida que las va leyendo:
bash -xv prueba.sh
El resultado es:
#!/bin/bash
# Shell script de prueba
N=5
+ N=5
echo “El valor de N es: $N”
+ echo ‘El valor de N es: 5'
El valor de N es: 5
Otros ejemplos
1.- Depurando todo el programa
Ejecución:
Ejemplo de guion de shell que interacciona con el usuario con las órdenes echo
y read.
Del mismo modo que lo hacen la mayoría de las órdenes, los guiones de shell
pueden aceptar parámetros cuando se ejecutan. Un parámetro o argumento es un
valor que le damos al guion de shell en el momento de su llamada. Los argumentos de
un shell script se pueden referenciar dentro del programa mediante una serie
de variables especiales.
Variables especiales
Al ejecutar un guion de shell con parámetros, hay un conjunto de variables
especiales del shell llamadas parámetros posicionales que se fijan automáticamente
para que coincidan con los parámetros dados en el programa. Se llaman parámetros
posicionales porque la asignación de cada variable depende de la posición de un
parámetro en la línea de comandos. Los nombres de estas variables se corresponden
con el valor numérico de su situación en la línea de comandos: 0, 1, 2, 3 ... Y así hasta
el último parámetro que se pasa.
Los parámetros posicionales se pueden utilizar dentro del guion de shell como
cualquier otra variable del shell, es decir, para saber su valor utilizaremos el
símbolo $. A partir del décimo parámetro, el número debe cerrarse entre llaves.
Los parámetros dentro del programa son accesibles utilizando las
variables: $0, $1, $2, $3... ${10}, ${11}, ${12}...
Ejemplo de uso de parámetros en un shell script
Crea un shell script que se llame args.sh con el siguiente contenido:
#! /bin/bash
# args.sh
# Ejemplo de uso de parámetros
echo “Nombre del guion de shell: $0"
echo “Valor del primer parámetro del guion de shell: $1"
echo “Valor del segundo parámetro del guion de shell: $2"
echo “Valor del tercer parámetro del guion de shell: $3"
Observación: podemos poner `basename $0` para evitar mostrar la ruta
entera.
Ejecútalo:
. /args.sh a b c
La salida del programa es la siguiente:
Nombre del guion de shell: ./args.sh
Valor del primer parámetro del guion de shell: a
Valor del segundo parámetro del guion de shell: b
Valor del tercer parámetro del guion de shell: c
Número de parámetros pasados al guion de shell: 3
Lista de todos los argumentos recibidos: a b c
Códigos de salida
Al finalizar la ejecución todas las órdenes generan un código de salida (en
inglés, exit status o exit code) que es un número entero entre 0 y 255.
Por convención, si la orden acaba bien, normalmente devuelve un cero (0) y si
acaba mal devuelve un valor distinto de cero (entre 1 y 255). Muchas veces, el valor
devuelto por la orden representa el error generado. Por ejemplo, los errores de
sintaxis casi siempre hacen que las órdenes devuelvan el valor 1.
El shell nos proporciona una variable especial llamada “?” (signo de
interrogación sin las comillas), que contiene el código de salida de la orden ejecutada
anteriormente.
Del mismo modo que lo hacen las órdenes, los shell scripts devuelven un código
de salida que es el de la última orden ejecutada. El código de salida de un shell
script también se puede consultar justo después de la finalización del programa
mediante la variable $?
Puedes modificar el guion y añadir al final una orden que dé error para
comprobar el efecto que tiene sobre el código de salida.
Orden exit
La orden exit provoca la finalización del shell script y de manera opcional
permite fijar el código de salida con un valor determinado. Su sintaxis es:
exit [n] siendo n un número entero entre 0 y 255.
Por convención el valor que se devuelve es un cero si ha ido bien o un entero
del rango entre 1 y 255 si ha habido algún error. Normalmente, el rango de 126 a 255
se reserva para ser utilizado directamente por el shell o para fines especiales, y los
códigos del rango de 0 a 125 se dejan para ser utilizados por el programa.
En todo guion de shell conviene proporcionar un código de salida significativo,
al menos un 0 (cero) si finaliza bien y un 1 (en general, un valor distinto de cero) si hay
algún error. Esto permitirá que el proceso que ha hecho la llamada pueda verificar
cómo ha ido la ejecución del guion de shell.
Si no se pasa ningún parámetro a exit, el código devuelto por el guion
de shell es el de la última orden ejecutada justo antes del exit. Por ejemplo:
#!/bin/bash
orden_1
...
orden_N
# Termina con el código de salida del orden_N.
exit
El ejemplo anterior, habría sido exactamente igual si se hubiera especificado el
valor del código de retorno de la siguiente manera:
#!/bin/bash
orden_1
...
orden_N
# Termina con el código de salida del orden_N.
exit $?
Análogamente, si un shell script finaliza sin especificar la orden exit, el código
de retorno es el de la última orden ejecutada al shell script.
#!/bin/bash
orden_1
...
orden_N
# Termina con el código de salida del orden_N.
Ejemplo de utilización del orden exit y comprobación de los códigos de salida.
#!/bin/bash
echo "Esto es una prueba."
# Devolvemos código de salida
exit 115
ANTONIO J. LEÓN DELGADO
49
UD 01: Scripting con bash
Guarda el archivo, dale permisos y ejecútalo.: /salida.sh
La salida del programa es la siguiente:
Esto es una prueba.
Visualiza el código de salida del guion de shell:
echo $?
El valor de salida es 115: lo hemos forzado con la orden exit 115
En la programación de guiones de shell es muy frecuente utilizar el
comando exit para finalizar el programa en cualquier punto sin seguir la norma de la
programación estructurada que dice que un programa debe tener un único punto de
salida. Por ejemplo, un shell script hecho con programación estructurada sería así:
if condicion_error1; then
código=1
else
if condicion_error2; then
código=2
else
if condicion_error3; then
código=3
else
# No hay errores
instrucciones
código=0
fi
fi
fi
exit $código
Orden let
La orden let permite a los programas de shell evaluar expresiones aritméticas
con los mismos operadores que en el mecanismo de expansión aritmética y con la
siguiente sintaxis:
let expressión_aritmética
La orden evalúa de izquierda a derecha la expresión y devuelve un código de
salida igual a 0 (verdadero) o 1 (falso). A pesar de que no siempre hay que cerrar la
expresión entre comillas dobles, podemos optar por ponerlas por defecto para evitar
errores.
La expresión aritmética puede constar de números enteros, variables y
operadores del shell. También podemos utilizar paréntesis para cambiar el orden de
preferencia de una expresión. Por ejemplo:
#! /bin/bash
# Definición de variables
x=12
y=2
# Utilización del orden let
let “z = x / y + 1"
echo $z # z vale 7, primero se ha hecho la división
# Alterar precedencia con paréntesis
let "z = x / (y + 1)"
echo $z # z vale 4, primero se ha hecho la suma
Al igual que con el orden let, las variables utilizadas como operandos en una
expresión pueden ir precedidas del símbolo $ o no. Por ejemplo, las dos expresiones
siguientes son correctas:
(( x = x + 1 )) # Correcto
(( x = $x + 1 )) # Correcto
Pero ten cuidado y no cometas errores como este:
(($x = x + 1)) #Incorrecto !!
ANTONIO J. LEÓN DELGADO
52
UD 01: Scripting con bash
Orden test
La orden test evalúa expresiones lógicas y genera un código de salida que indica
si la expresión es cierta (código de salida igual a cero) o falsa (código de salida distinto
de cero). Esta orden no escribe nada en la salida estándar. Para determinar el
resultado de la orden test hay que evaluar el valor del código de salida con la
variable “?”.
La sintaxis de la orden test es la siguiente:
test expresión_test
O en forma abreviada:
[ expresión_test ]
Observación: hay que dejar un espacio después del símbolo [ y antes del
símbolo]
En las siguientes tablas puedes ver las expresiones que se pueden evaluar con
test.
Números enteros
Ejemplos
Orden Test
Ficheros
Observación: probar alguna de estas opciones para comprobar cómo se
comportan las diferentes opciones. Por ejemplo, las opciones –w, -r y –x se refieren a
los propietarios y grupos propietarios de los ficheros consultados.
Un ejemplo:
Ejemplo
Observación:
if [[ $i == A* ]] ; then
….
Está comparado $i y será verdadero si $i empieza por A.
Ojo: doble corchete.
Ejemplos
1.- Usa test para evaluar estas cadenas
$cadena1=”rojo”
4cadena2=”verde”
$test “$cadena1” = “$cadena2”
$echo $?
1
$test “$cadena1” = “rojo”
$echo $?
0
2.- Con la orden test, comprueba si el número 11 es mayor que el número 15.
ANTONIO J. LEÓN DELGADO
56
UD 01: Scripting con bash
test 11 -gt 15
Evalúa el código de salida de la orden que acabas de ejecutar para saber si la
expresión anterior es verdadera (0) o falsa (diferente de 0):
echo $?
1
La salida es un 1, lo que indica que la expresión "11 es mayor que 15" es falsa.
3.- Con la forma abreviada del orden test, comprueba si el número 15 es igual
que el número 15.
[ 15 -eq 15 ]
Evalúa el código de salida de la orden que acaba de ejecutar para saber si la
expresión anterior es verdadera (0) o falsa (diferente de 0):
echo $?
0
La salida es un 0, lo que indica que la expresión "15 es igual que 15" es cierta.
Estructuras de control
ANTONIO J. LEÓN DELGADO
58
UD 01: Scripting con bash
Las estructuras de control (if, case, while, for, etc.) permiten cambiar el flujo
secuencial de un programa en función de la evaluación de unas condiciones y
bifurcarse hacia un lado o hacia otro o repetir la ejecución de unas instrucciones.
A menudo utilizamos la orden test abreviada con corchetes o la construcción
doble paréntesis para evaluar expresiones y tomar decisiones.
Pero ni los corchetes de la orden test ni los paréntesis de la construcción
doble paréntesis forman parte de la sintaxis de ninguna estructura de
control del shell. No lo confundas con otros lenguajes de programación en que la
especificación de condiciones en las estructuras de control debe hacerse entre
paréntesis porque la sintaxis lo requiere.
Estructuras alternativas
Las estructuras alternativas son aquellas que nos permiten ejecutar una parte
del programa en función de si se cumple o no una condición.
Estructura if
La estructura if proporciona un control de flujo basado en el código de retorno
de una orden. La sintaxis es:
if condición; then
orden1
orden2
...
órdenes
fi
El shell ejecuta la orden que establece la condición posterior a if y evalúa el
código de retorno resultante:
Si el valor del código de retorno es igual a cero, entonces se ejecutan las
órdenes que haya entre las palabras clave then y fi.
Si el valor del código de retorno es diferente de cero, no se ejecutan las
órdenes que haya entre las palabras clave then y fi y el programa sigue
ejecutando el que haya detrás de la palabra clave fi.
Habitualmente utilizamos las órdenes test y let (o el doble paréntesis
equivalente) para especificar las condiciones. Por ejemplo, el código siguiente
comprueba si existe el fichero /etc/passwd:
if test -f /etc/passwd ; then
echo "El archivo /etc/passwd existe."
fi
O bien con la forma abreviada de test:
if [ -f / etc/passwd ] ; then
echo "El archivo /etc/passwd existe."
fi
Pero la sintaxis de if acepta cualquier orden (todas las órdenes generan un
código de retorno). Por ejemplo:
if $(grep ^root /etc/passwd > /dev/null) ; then
echo "El usuario root existe."
fi
Equivalente:
if `grep ^root /etc/passwd > /dev/null` ; then
echo "El usuario root existe."
ANTONIO J. LEÓN DELGADO
59
UD 01: Scripting con bash
fi
Equivalente:
if grep ^root /etc/passwd > /dev/null ; then
echo "El usuario root existe."
fi
Equivalente:
if (grep ^root /etc/passwd > /dev/null) ; then
echo "El usuario root existe."
fi
#!/bin/bash
# Control del número de parámetros
if [ $# -ne 1 ] ; then
echo "Número de argumentos erróneo."
echo "Uso del programa: $0 nombre"
exit 1
fi
#
# Comprobar si el parámetro es un archivo
if [ -f $1 ] ; then
echo "$1 es un archivo."
fi
exit 0
Estructura if-else
La estructura if-else permite tomar un curso de acción si el código de retorno
de la orden que controla la condición es cero (verdad) y otro curso de acción si el
código de retorno es diferente de cero (falso). La sintaxis es la siguiente:
if condición; then
orden 1
else
orden2
fi
Para ver el funcionamiento hacemos un guion de shell sencillo que pida la
entrada de un número por teclado y que a continuación nos diga si el número leído es
igual a 10 o no:
#!/bin/bash
echo "Introduce un número:"
read X
if [ "$X " –eq 10 ] ; then
echo "El número es igual a 10."
else
echo "El número no es igual a 10."
fi
Si el usuario no introduce nada, el programa daría un aviso.
Estructura if-elif-else
La estructura if-elif-else se puede utilizar para construir una bifurcación con
múltiples direcciones. La sintaxis es:
if condición 1; then
ANTONIO J. LEÓN DELGADO
63
UD 01: Scripting con bash
orden1
elif condición 2; then
orden2
elif condición 3; then
orden3
...
else
ordenN
fi
Nótese que la manera recomendada de tabular la estructura if-elif-else es
diferente de lo habitual.
Con esta estructura if-else-if, el shell evalúa las expresiones condicionales
empezando por la primera y continuando por la siguiente de forma descendente hasta
encontrar una condición verdadera (código de retorno igual a cero), momento en que
ejecuta la lista de comandos asociada a esta condición y se salta el resto de la
escalera. Si ninguna condición es verdadera se ejecutarán las órdenes asociadas
al else final. Si todas las condiciones son falsas y no hay else final, no hace nada.
En realidad, la estructura if-then-elif no es más que una manera abreviada de
escribir el mismo código con estructuras if-else anidadas, es decir, es equivalente a lo
siguiente:
if condición1; then
ord1
else
if condición2; then
ord2
else
if condicion3; then
ord
else
if
...
else
ord
fi
fi
fi
fi
Fíjate en la forma que adopta el código cuando se implementa con
estructuras if-else y se tabula de la manera habitual.
Por ejemplo, el programa siguiente lee un número del teclado y muestra por
pantalla si es más pequeño, mayor o igual que 10, utilizando una estructura if-elif-else:
Estructura case
La estructura case es útil cuando tenemos múltiples bifurcaciones. Su sintaxis
es:
case "$nombre_var " in
patrón 1)
orden1
...
órdenes
ANTONIO J. LEÓN DELGADO
66
UD 01: Scripting con bash
;;
patrón 2)
orden1
...
órdenes
;;
...
patrones)
orden1
...
órdenes
;;
esac
Nótese el uso del patrón * , que se puede utilizar para indicar cualquier cosa.
Operadores && y ||
Los operadores de control && (AND) y || (OR) permiten realizar un control de
flujo básico.
Operador &&
El operador && utiliza para ejecutar una orden, y, si tiene éxito (código de
salida igual a cero), ejecutar la próxima orden de la lista. La sintaxis es:
orden1 && orden2
La orden2 ejecuta sí y sólo si la orden1 devuelve un estado de salida de cero
(verdadero). En otras palabras, se ejecuta orden1 si el código de salida es igual a cero,
entonces se ejecuta orden2. Es decir, es equivalente a la utilización de la
estructura if así:
ANTONIO J. LEÓN DELGADO
69
UD 01: Scripting con bash
if orden1; then
orden2
fi
Por ejemplo:
rm/tmp/archivo && echo "Archivo borrado."
La orden echo sólo se ejecuta si la orden rm ejecuta con éxito (con un código de
salida de cero). Si el archivo se elimina correctamente, la orden rm da un código de
salida igual a cero ya continuación se muestra el mensaje "Archivo borrado". Para
evitar los posibles mensajes de error de la orden rm, podemos redirigir la salida de
errores a / dev / null así:
rm/tmp/archivo 2> / dev/null && echo "Archivo borrado."
operador ||
El operador ||utiliza para ejecutar una orden, y, si no tiene éxito (código de
salida distinto de cero), ejecutar la próxima orden de la lista. La sintaxis es:
orden1 || orden2
La orden2 ejecuta sí y sólo si el orden1 devuelve un estado de salida diferente
de cero. En otras palabras, se ejecuta orden1, si el código de salida de orden1 es
diferente de cero, entonces se ejecuta orden2. Por ejemplo:
cat / etc/shadow 2> /dev/null || echo "No se pudo abrir el archivo."
La orden cat intentará leer el fichero /etc/shadow y si falla mostrará el mensaje
"No se pudo abrir el archivo".
Ejemplo de utilización del operador OR
Escribir las órdenes necesarias para buscar el nombre de un usuario llamado
"pepe" en /etc/passwd y dar un mensaje si no se encuentra.
grep "^pepe" /etc/passwd || echo "No se encontró pepe en /etc/passwd."
Escribir las órdenes necesarias para asegurarse de que root es quien está
ejecutando el guion de shell y dar un mensaje dependiendo de si lo es o no.
test $(id -u) -eq 0 && echo "Se ejecuta el script con el superusuario root." ||
echo "Sólo el usuario root puede ejecutar este script."
Estructuras iterativas
Las estructuras iterativas son aquellas que nos permiten ejecutar varias veces
una parte de código.
Estructura while
La estructura while permite la ejecución repetitiva de unas sentencias siempre
que la orden de control del bucle while sea cierta (código de salida igual a cero). La
sintaxis es:
while condición; do
orden1
orden2
...
ordenn
done
ANTONIO J. LEÓN DELGADO
71
UD 01: Scripting con bash
Normalmente, se utilizan las órdenes test o let para controlar la condición del
bucle, pero podemos utilizar cualquier orden que devuelva un valor.
Veamos un ejemplo sencillo, un bucle que muestra por pantalla los números
del 1 al 10.
Con doble paréntesis:
Con let:
Estructura until
La estructura until es idéntica a while, excepto que la condición es la
complementaria del while. La lista de comandos se ejecuta siempre que la condición
devuelva un código de salida distinto de cero.
Sintaxis:
until condición; do
orden1
orden2
...
done
Por ejemplo:
X=1
until (( X >10 ) ) ; do
echo “X vale $X”
((X = X + 1))
ANTONIO J. LEÓN DELGADO
73
UD 01: Scripting con bash
done
Estructura for
La estructura for permite especificar una lista de valores y ejecutar las
sentencias para cada valor de la lista. La sintaxis de este bucle es la siguiente:
for nombre_var in lista_de_valores; do
orden1
orden2
...
ordenn
done
La lista de valores es una secuencia de valores separados por espacio o
tabulador que se irán asignando a la variable nombre_var en cada iteración del
bucle for. Por tanto, las sentencias que hay entre las palabras reservadas do y done,
se ejecutarán tantas veces como valores haya en la lista de valores.
La construcción clásica de bucle for del shell difiere significativamente de la de
su homólogo C y otros lenguajes de programación.
Por ejemplo, el siguiente es un bucle for que simplemente muestra el valor de
cada uno de los ítems de la lista de valores (muestra los números del 1 al 5):
for X in 1 2 3 4 5; do
echo $X
done
Ejecución:
Ejecución:
Funciones
Ficheros de funciones
Hay un montón de scripts en el sistema que utilizan las funciones como una
manera estructurada de agrupar una serie de órdenes. En algunos sistemas Linux, por
ejemplo, se encuentra el archivo /etc/rc.d/init.d/functions, un archivo de definición
de funciones que incluye el principio de todos los scripts de inicio. Usando este
método, las tareas comunes, como la comprobación de si un proceso se ejecuta, iniciar
o detener un demonio, etc., basta escribirlas una vez.
Como administradores del sistema, podemos crear un archivo de funciones, por
ejemplo /usr/local/bin/funciones, con todas las funciones que utilizarás con
frecuencia en tus guiones de shell. Luego, en cada guion que tenga que utilizar las
funciones, simplemente escribes la línea siguiente:
. /usr/local/bin/funciones
No dejes de poner el punto y el espacio (equivalente a la orden source) antes
del nombre del archivo que contiene las funciones para que el shell actual reconozca
las funciones.
La sintaxis para definir una función es:
function nombre_de_la_funcion {
código de la función
}
O bien:
nombre_de_la_funcion ( ) {
código de la función
}
Hay que tener en cuenta las siguientes consideraciones:
El nombre de la función debe ser único en el shell o script.
El carácter { de apertura de la función puede estar en la segunda línea.
La definición de la función debe estar hecha antes de la primera llamada a la
función que haya en el programa.
Ejemplo
# Programa principal
saludaUsuario
mostrarFecha
Ejecución:
if [ -z $DIR ] ; then
echo "$0: especifique el nombre del directorio."
exit 1
fi
if [ ! -d $DIR ] ; then
echo "$0: el directorio no existe."
exit 1
fi
Cuando esto sucede, es mejor que cree una función para este propósito, por
ejemplo:
mostrarError ( ) {
echo "$0:$*"
exit 1
}
...
if [ -z "$DIR" ] ; then
mostraError "especifique el nombre del directorio."
fi
if [ ! -d " $DIR " ] ; then
mostrarError "el directorio no existe."
fi
Códigos de retorno
Las funciones siempre devuelven un valor al shell que las llama llamado código
de retorno, que es análogo al código de salida de las órdenes. El código de retorno de
una función puede ser especificado de manera explícita con el orden return.
De otro modo, el valor devuelto por la función es el valor del código de salida
de la última orden ejecutada. El código de retorno de la función puede utilizarse en