08.05.2013 Views

Programación en Bash

Programación en Bash

Programación en Bash

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Introducción<br />

<strong>Programación</strong> <strong>en</strong> <strong>Bash</strong><br />

Visto <strong>en</strong>: xtech.com.ar<br />

Linux, así como la mayoría de los UNIX, utilizan shell scripts para realizar una infinidad de tareas. Un<br />

shell script es un programa que se escribe con una sintaxis particular, <strong>en</strong> un archivo de texto plano, para<br />

que sea interpretado por un shell, <strong>en</strong> este caso /bin/bash.<br />

Un shell script es básicam<strong>en</strong>te un programa que llama a otros programas, con la posibilidad de hacer<br />

algun tipo de procesami<strong>en</strong>to propio (como control de flujo, operaciones matemáticas simples, etc).<br />

Por lo tanto la forma de crear un shell script es hacer un archivo con nuestro ya querido vi:<br />

vi holam<br />

Luego lo ll<strong>en</strong>amos con las instrucciones que deseamos. Por ejemplo:<br />

#!/bin/bash<br />

echo "Hola mundo!"<br />

# Esto es por costumbre utilizado como ejemplo del primer programa.<br />

# Se dice que trae suerte!<br />

Luego le damos permisos de ejecución a ese archivo:<br />

chmod +x holam<br />

Y de esta manera ya t<strong>en</strong>dremos listo un shell script que se ejecuta de la sigui<strong>en</strong>te forma:<br />

./holam<br />

Debemos destacar la primera linea de nuestro script bash:<br />

#!/bin/bash<br />

esta línea le indica al sistema que el script será interpretado por el programa que se <strong>en</strong>cu<strong>en</strong>tra a<br />

continuación de #!, <strong>en</strong> este caso, /bin/bash<br />

Las últimas dos líneas son com<strong>en</strong>tarios<br />

# Esto es por costumbre utilizado como ejemplo del primer programa.<br />

# Se dice que trae suerte!<br />

Los com<strong>en</strong>tarios comi<strong>en</strong>zan con # y se exti<strong>en</strong>d<strong>en</strong> hasta el final de la línea. Es muy útil ir com<strong>en</strong>tando el<br />

código que uno escribe, para recordar qué realizan ciertas funciones o algoritmos, y otra persona pueda<br />

compr<strong>en</strong>der el funcionami<strong>en</strong>to de nuestro script.<br />

Variables<br />

Las variables <strong>en</strong> un script BASH son simplem<strong>en</strong>te id<strong>en</strong>tificadores, sin tipo. Para asignar un valor a una<br />

variable, se utiliza el operador =, por ejemplo:<br />

[usuario@localhost]$ MIVARIABLE=4


Por conv<strong>en</strong>ción, los nombres de las variables se usan <strong>en</strong> mayúsculas, aunque no es obligatorio.<br />

Para usar el cont<strong>en</strong>ido de la variable, d<strong>en</strong>tro de un script, se usa el operador $. Por ejemplo:<br />

[usuario@localhost]$ echo $MIVARIABLE<br />

4<br />

[usuario@localhost]$<br />

Para utilizar el cont<strong>en</strong>ido de una variable, seguida de un texto, debemos usar las llaves {}<br />

Consideremos este ejemplo:<br />

ARCHIVO="/tmp/ej"<br />

mv $ARCHIVO $ARCHIVO-bak<br />

En este caso, bash interpretaría a $ARCHIVO y $ARCHIVO-bak como dos variables distintas, para<br />

evitar esto debemos reescribirlo de esta manera:<br />

ARCHIVO="/tmp/ej"<br />

mv $ARCHIVO ${ARCHIVO}-bak<br />

Comillas<br />

En el shell, el espacio, o el tab, son separadores. Es decir, que cuando al shell le indicamos<br />

ls -l hola que tal<br />

Lo interpreta como que le pedimos que nos de información sobre tres archivos, llamados: hola, que, y<br />

tal.<br />

Si <strong>en</strong> realidad, lo que queríamos, era información sobre un archivo llamado "hola que tal", <strong>en</strong>tonces<br />

hay varias maneras de indicarle al shell que los espacios <strong>en</strong>tre esas palabras no deb<strong>en</strong> ser separadores.<br />

Escape ( \ )<br />

Hay un caracter de escape, que indica al shell que el sigui<strong>en</strong>te carácter no es especial. Y es la barra<br />

invertida. Por lo tanto, podríamos obt<strong>en</strong>er la información del archivo "hola que tal" de la sigui<strong>en</strong>te<br />

forma:<br />

ls -l hola\ que\ tal<br />

Los espacios no son especiales, no son separadores, y "hola que tal" es una sola palabra.<br />

Algunos caracteres especiales más:<br />

\ @ ! | < > [ ] { } ( ) ? * $ ' ^ ` " # & ;<br />

Por lo tanto, si queremos incluir la \ <strong>en</strong> alguna parte, <strong>en</strong>tonces debemos ponerla 2 veces (\\), la primera<br />

para decirle a BASH que no tome como carácter especial lo que sigue y la segunda como ese carácter<br />

que queremos incluír. Esto es muy común <strong>en</strong> casos como:<br />

cd algún\ directorio\ con\ espacios


Comillas dobles ( " " )<br />

Las comillas dobles hac<strong>en</strong> que los espacios <strong>en</strong>tre las comillas no sean especiales. Por lo tanto,<br />

podríamos haber utilizado:<br />

ls -l "hola que tal"<br />

Todos los otros carácteres sigu<strong>en</strong> si<strong>en</strong>do especiales.<br />

Comillas simples ( ' ' )<br />

Las comillas simples logran que ningún caracter (salvo la comilla simple misma) sea especial. Por<br />

ejemplo, si quisieramos crear un archivo que se llame *@$&, lo debemos hacer rodeándolo de comillas<br />

simples:<br />

touch '*@$&'<br />

Si queremos poner una comilla simple, debemos "escaparla". Para crear un archivo llamado que'tal,<br />

deberíamos hacerlo así:<br />

touch 'que\'tal'<br />

Ya que si no lo hacemos, la segunda comilla "cierra" la primera!<br />

Comilla invertida ( ` ` )<br />

Las comillas invertidas son más raras. Deb<strong>en</strong> rodear un comando. Ese comando será ejecutado, y lo<br />

que ese comando imprima reemplazará al cont<strong>en</strong>ido de las comillas invertidas. Tal vez lo más s<strong>en</strong>cillo<br />

sea un ejemplo:<br />

[usuario@localhost]$ ls<br />

experto.aux experto.log experto.lyx experto.pdf experto.tex<br />

experto.dvi #experto.lyx# experto.lyx~ experto.ps experto.toc<br />

[usuario@localhost]$ V=`ls`<br />

[usuario@localhost]$ echo $V<br />

experto.aux experto.log experto.lyx experto.pdf experto.tex<br />

experto.dvi #experto.lyx# experto.lyx~ experto.ps experto.toc<br />

[usuario@localhost]$<br />

El uso más frecu<strong>en</strong>te de las comillas invertidas es poder asignar el "resultado" de un comando a una<br />

variable.<br />

Control de flujo<br />

Esto refiere al cauce o flujo normal de los programas. No siempre hay un solo camino a seguir y estas<br />

proposiciones permit<strong>en</strong> que el programa realice distintas tareas, según las condiciones de las variables a<br />

interpretar.<br />

"if"<br />

El"if" es un proposición de control que verifica si es verdadera o falsa una condición.<br />

Sintaxis:


if comando-condición<br />

th<strong>en</strong><br />

Comandos si la condición es verdadera<br />

else<br />

Comandos si la condición es falsa<br />

fi<br />

Es importante que la ubicación de las lineas se mant<strong>en</strong>ga, ya que las proposiciones if/th<strong>en</strong>/else/fi se<br />

controlan línea por línea. La parte else es opcional. En caso de querer hacer todo el control <strong>en</strong> una sola<br />

línea, las proposiciones deberán estar separadas por un punto y coma (;).<br />

Los comandos que estén debajo del th<strong>en</strong> se ejecutarán si la condición dio verdadera. Esto quiere decir<br />

que el valor de retorno de la condición fue 0 (cero). En caso contrario se ejecutarán los comandos que<br />

le sigu<strong>en</strong> al else, si es que se utilizó esta proposición.<br />

En la condición se puede poner un comando, donde la ejecución del mismo (su valor de retorno)<br />

definirá qué comandos (de qué proposición) se ejecutarán.<br />

Si se verifica una condición, se deberán utilizar los corchetes para mayor compr<strong>en</strong>sión.<br />

Ejemplos:<br />

(utilizando comandos) El hecho de <strong>en</strong>tregar algo como salida se toma como condición lógica<br />

verdadera.<br />

if ps ax | grep httpd | grep -v grep<br />

th<strong>en</strong><br />

echo "El web server está funcionando"<br />

else<br />

echo "El web server NO esta funcionando"<br />

fi<br />

(utilizando condiciones)<br />

if [ -w /etc/passwd ]<br />

th<strong>en</strong><br />

echo "T<strong>en</strong>go permisos de escritura <strong>en</strong> el archivo /etc/passwd"<br />

else<br />

echo "NO t<strong>en</strong>go permisos de escritura <strong>en</strong> el archivo /etc/passwd"<br />

fi<br />

Puede suceder que t<strong>en</strong>gamos que testear mas de una condicion, para esto, podemos utilizar la sigui<strong>en</strong>te<br />

estructura:<br />

if condición1<br />

th<strong>en</strong><br />

Comando1<br />

Comando2<br />

elif condición2<br />

th<strong>en</strong><br />

Comando1<br />

Comando2<br />

else<br />

Comando-por-defecto #Ninguna de las condiciones anteriores es verdadera<br />

fi<br />

Esta es una manera de abreviar varias estructuras if - th<strong>en</strong> - else - if <strong>en</strong> una sola, pudi<strong>en</strong>do utilizarse<br />

más de dos condiciones.


La estructura de control if, es muy utilizada con test, que no es más que una operación de<br />

comparación, <strong>en</strong> las condiciones que se requieran.<br />

"case"<br />

El "case" es una proposición que puede analizar y validar varios casos (opciones) del valor de una<br />

variable.<br />

Sintaxis<br />

case variable in<br />

patrón | patrón)<br />

Comando;<br />

Comando;<br />

Comando;;<br />

patrón | patrón)<br />

Comando;<br />

Comando;<br />

Comando;;<br />

*)<br />

Comandos si ningún otro valor fue igualado;;<br />

esac<br />

El case es raram<strong>en</strong>te usado, pero es muy efici<strong>en</strong>te <strong>en</strong> algunos casos.<br />

Ejemplos:<br />

case $mes in<br />

<strong>en</strong>e*|Ene*)<br />

echo "Mes de Enero";;<br />

feb*|Feb*)<br />

echo "Mes de Febrero";;<br />

mar*|Mar*)<br />

echo "Mes de Marzo";;<br />

*)<br />

echo "Algún otro mes!";;<br />

esac<br />

Ciclos<br />

Los ciclos conti<strong>en</strong><strong>en</strong> secciones del programa que se repetirán una determinada cantidad de veces o<br />

hasta que alguna condición cambie.<br />

for<br />

El for debe ser el ciclo más utilizado, es muy práctico cuando se trabaja con shell scripts.<br />

A difer<strong>en</strong>cia de los l<strong>en</strong>guajes de programación más comunes, un ciclo for d<strong>en</strong>tro de un shell script<br />

realiza una acción dada sobre cada uno de los elem<strong>en</strong>tos de una lista, y no sobre una variable que se va<br />

increm<strong>en</strong>tando <strong>en</strong> cada ciclo.<br />

La variable utilizada <strong>en</strong> el for (<strong>en</strong> este caso $i) es reemplazada por cada una de las palabras de la lista,<br />

<strong>en</strong> cada ciclo del for.<br />

Sintaxis:


for i in lista de palabras<br />

do<br />

cuerpo del ciclo, $i ti<strong>en</strong>e el valor de elem<strong>en</strong>tos sucesivos de la lista<br />

done<br />

Ejemplos:<br />

for i in `ls -1 /tmp`<br />

do<br />

echo $i<br />

rm -i $i<br />

done<br />

En este ciclo, el comando ls -1 /tmp, g<strong>en</strong>erará una lista de todos los archivos que exist<strong>en</strong> <strong>en</strong> el<br />

directorio /tmp. D<strong>en</strong>tro del cuerpo del ciclo imprimimos el cont<strong>en</strong>ido de la variable y luego<br />

preguntamos si se desea borrar ese archivo (opción -i del comando rm).<br />

while<br />

Este ciclo utiliza la condición de terminación de un comando (valor de retorno) para controlar la<br />

ejecución de los comando d<strong>en</strong>tro del ciclo. Termina la ejecución del ciclo, cuando el comando<br />

devuelve falso (algo difer<strong>en</strong>te a 0).<br />

Sintaxis:<br />

while comando<br />

do<br />

cuerpo del ciclo ejecutado a condición de<br />

que el comando devuelva verdadero<br />

done<br />

Ejemplos:<br />

while sleep 60<br />

do<br />

who | grep daniel<br />

done<br />

En este ejemplo, cada 60 segundos (definidos por el comando sleep 60), verificará si el usuario daniel<br />

ha ingresado al equipo. En caso de que lo haya hecho, el listado del who saldrá por pantalla (cada 60<br />

segundos).<br />

until<br />

Este ciclo se comporta de una manera muy similar al anterior, ya que define su control dep<strong>en</strong>di<strong>en</strong>do del<br />

comando que ejecuta (si éste da verdadero, se sigue ejecutando el ciclo).<br />

Sintaxis:<br />

until comando<br />

do<br />

cuerpo del ciclo ejecutado a condición<br />

de que el comando devuelva falso.<br />

done<br />

Ejemplo:


until who | grep daniel<br />

do<br />

sleep 60<br />

done<br />

En este ejemplo, a difer<strong>en</strong>cia del ejemplo del ciclo while, el ciclo ejecuta primero el comando, de esta<br />

forma no es necesario esperar 60 segundos para saber si el usuario daniel esta logueado <strong>en</strong> el equipo (si<br />

el usuario esta logueado, el ciclo termina).<br />

Argum<strong>en</strong>tos<br />

Los argum<strong>en</strong>tos sirv<strong>en</strong> para pasarle a un programa o una función valores desde la línea de comando.<br />

Ejemplo:<br />

Variable Descripción<br />

$# Número de argum<strong>en</strong>tos<br />

$* Todos los argum<strong>en</strong>tos del shell<br />

$- Opciones suministradas al shell<br />

$? Valor de retorno del último comando ejecutado<br />

$$ Id<strong>en</strong>tificación del PID (número de proceso)<br />

$0 Nombre del script<br />

$1 Primer argum<strong>en</strong>to<br />

$n Argum<strong>en</strong>to "n"<br />

#!/bin/sh<br />

#<br />

# Programa que recibe argum<strong>en</strong>tos y los imprime por pantalla<br />

echo "\$*: $*"<br />

echo "\$#: $#"<br />

echo "\$0: $0"<br />

echo "\$1: $1"<br />

echo "\$2: $2"<br />

Notas sobre el ejemplo:<br />

En la líneas de impresión (echo), para imprimir el símbolo "$" (pesos) se ti<strong>en</strong>e que anteponer el<br />

símbolo "\" (contra barra), sino el shell lo va a interpretar como una variable, y si esta existe imprimirá<br />

su cont<strong>en</strong>ido.<br />

Funciones<br />

Las funciones son un recurso es<strong>en</strong>cial para la bu<strong>en</strong>a programación, permit<strong>en</strong> escribir una sola vez un<br />

pedazo de código que se repita varias veces <strong>en</strong> el script, y así, minimizar el marg<strong>en</strong> de error y también<br />

la cantidad de líneas <strong>en</strong> el programa.<br />

Para utilizarlas simplem<strong>en</strong>te se hace un llamado a la función. Las funciones pued<strong>en</strong> estar d<strong>en</strong>tro del<br />

mismo shell script, o <strong>en</strong> un archivo aparte. Cuando se escrib<strong>en</strong> las funciones <strong>en</strong> un archivo aparte, es<br />

muy importante utilizar el comando "." (punto) para cargarlas <strong>en</strong> memoria. Si no se cargan <strong>en</strong> memoria<br />

de esta manera, las funciones no estarán disponibles.


Ejemplo:<br />

#<br />

# Cargando las funciones <strong>en</strong> memoria<br />

#<br />

. /home/jose/funciones/funciones-arch.sh<br />

Uso<br />

La sintaxis para utilizar funciones es muy s<strong>en</strong>cilla y no agrega mayor dificultad. El modo de uso se<br />

remite a definir la función especificando el nombre y par<strong>en</strong>tesis que abr<strong>en</strong> y cierran. Todos los<br />

comandos que involucran la función se <strong>en</strong>cierran con llaves.<br />

Ejemplo:<br />

(archivo: lib/arch.sh)<br />

#<br />

# Funciones para manipulación de archivos<br />

#<br />

borrar ()<br />

{<br />

arch=$1<br />

if [ -z "$arch" ]<br />

th<strong>en</strong><br />

echo "No se recibió ningún archivo"<br />

return 2<br />

else<br />

if [ -f "$arch" ]<br />

th<strong>en</strong><br />

if [ -w "$arch" ]<br />

th<strong>en</strong><br />

rm -i $arch<br />

else<br />

echo "No t<strong>en</strong>go permisos para borrar $arch"<br />

fi<br />

else<br />

echo "$arch no es un archivo"<br />

fi<br />

fi<br />

}<br />

(archivo: principal.sh)<br />

#!/bin/bash<br />

#<br />

# Programa ejemplo para el uso de funciones <strong>en</strong> shell script<br />

#<br />

#<br />

# Cargo las funciones <strong>en</strong> memoria<br />

#<br />

. lib/arch.sh<br />

dir=./<br />

for i in $dir/*<br />

do<br />

borrar $i<br />

done


Notas sobre el ejemplo:<br />

(archivo: lib/arch.sh)<br />

Esta función toma el archivo a borrar como argum<strong>en</strong>to (arch=$1), verifica que se le haya pasado un<br />

argum<strong>en</strong>to realm<strong>en</strong>te (if [ -z "$arch" ]), que un archivo pasado como argum<strong>en</strong>to sea regular (if [ -f<br />

"$arch" ]) y que t<strong>en</strong>ga permisos de escritura. En todos los casos de falsedad responde con un m<strong>en</strong>saje<br />

avisando el problema.<br />

(archivo: principal.sh)<br />

El programa hace un ciclo con los archivos de un directorio específico (for i in $dir/*) y se los pasa<br />

como argum<strong>en</strong>to a la función borrar.<br />

Valores de retorno<br />

Las funciones pued<strong>en</strong> devolver valores de error utilizando el comando "return<br />

Ejemplo:<br />

#!/bin/sh<br />

func () {<br />

return $1 }<br />

func 0<br />

echo "ret: ($?)"<br />

func 1<br />

echo "ret: ($?)"<br />

func 2<br />

echo "ret: ($?)"<br />

func 3<br />

echo "ret: ($?)"<br />

Variables locales a la función<br />

Existe la posibilidad de utilizar variables locales a la función, esto significa que la variable solam<strong>en</strong>te<br />

va a existir durante la ejecución de la función.<br />

Para crear una variable local a la función se utilizar el operador "local<br />

Ejemplo:<br />

func () {<br />

local x<br />

x=$1<br />

echo "D<strong>en</strong>tro de la función \$x vale ($x)"<br />

}<br />

echo "Antes de ejecutar la función \$x vale ($x)"<br />

func HOLA!!<br />

echo "Después de ejecutar la función \$x vale ($x)"<br />

Operaciones Aritméticas<br />

Exist<strong>en</strong> varias formas de calcular valores d<strong>en</strong>tro de un shell script. Tradicionalm<strong>en</strong>te, estos cálculos se<br />

hicieron con programas externos, esto g<strong>en</strong>eraba un retardo inm<strong>en</strong>so <strong>en</strong> la ejecución del shell script.<br />

Hoy los nuevos intérpretes tra<strong>en</strong> la posibilidad de hacer cálculos internam<strong>en</strong>te. Para esto se utiliza una


sintaxis especial, y es muy importante que los valores de las variables que utilic<strong>en</strong> para hacer estos<br />

cálculos sean números únicam<strong>en</strong>te.<br />

Uso<br />

La sintaxis para hacer operaciones aritméticas es la sigui<strong>en</strong>te:<br />

$[]<br />

Las operaciones que se pued<strong>en</strong> realizar son:<br />

• suma $((1+1))<br />

• resta $((2-1))<br />

• multiplicación $((2*2))<br />

• división $((2/2])<br />

• otras como suma de bits, sacar el módulo, evaluación de igualdad, etc.<br />

Ejemplo:<br />

#!/bin/sh<br />

#<br />

# Operaciones aritméticas<br />

#<br />

x=2<br />

tot=$[$x+1]<br />

echo "tot: ($tot)"<br />

bc<br />

A veces hay conjuntos de herrami<strong>en</strong>tas que nos su<strong>en</strong>an y no las aprovechamos al máximo. Quizás una<br />

de esas sea bc. La calculadora que podemos usar desde la consola, que aparte de sumar y restar puede<br />

realizar cálculos con una precisión de varios decimales, cambiar de base numérica o programarla, etc.<br />

veremos como...<br />

Si ejecutamos bc veremos:<br />

$ bc<br />

bc 1.06<br />

Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.<br />

This is free software with ABSOLUTELY NO WARRANTY.<br />

For details type `warranty'.<br />

Acá espera que trabajemos desde la <strong>en</strong>trada estándar, por ejemplo:<br />

4+8<br />

12<br />

scale=3<br />

27/68<br />

.397<br />

halt<br />

Sabe sumar (y restar, dividir, multiplicar; sin problemas).


Variables<br />

Si queremos que trabaje con decimales, asignaremos un valor a la variable scale.<br />

scale=3<br />

2/3<br />

.666<br />

También podemos hacer:<br />

scale=9;2/3<br />

.666666666<br />

Al ser scale una variable más, podemos consultar su valor s<strong>en</strong>cillam<strong>en</strong>te escribiéndola:<br />

scale<br />

3<br />

#o también usando print<br />

print scale<br />

3<br />

Otro ejemplo de usos de variables podría ser:<br />

scale=5<br />

variable=3<br />

100/variable<br />

33.33333<br />

Hay una variable especial llamada last, almac<strong>en</strong>a el resultado de la última operación:<br />

100/3<br />

33.33333<br />

last*2<br />

66.66666<br />

Cambios <strong>en</strong> la base numérica<br />

Hay dos variables especiales que son ibase y obase que defin<strong>en</strong> la base de <strong>en</strong>trada y de salida de los<br />

números, respectivam<strong>en</strong>te.<br />

Si queremos calcular el número 5 <strong>en</strong> base 10 (decimal) a base 2 (binario), haremos:<br />

obase=2<br />

5<br />

101<br />

Si queremos pasar de binario a hexadecimal:<br />

obase=16<br />

ibase=2<br />

11111111<br />

FF<br />

Otras operaciones matemáticas<br />

Podemos usar también sqrt, 2^3, etc.


Si queremos t<strong>en</strong>er operaciones matemáticas más complejas t<strong>en</strong>emos que ejecutar el bc -l para cargar<br />

la librería matemática:<br />

s (x) S<strong>en</strong>o de x, <strong>en</strong> radianes<br />

c (x) Cos<strong>en</strong>o de x<br />

a (x) Arcotang<strong>en</strong>te de x<br />

l (x) Logaritmo neperiano de x<br />

e (x) Expon<strong>en</strong>cial de x<br />

j (n,x) Función de Bessel de un <strong>en</strong>tero de ord<strong>en</strong> n de x<br />

Aplicación <strong>en</strong> un script<br />

Si queremos pedir que el usuario teclee algo por teclado, la función es read. Por tanto.<br />

variable=read()<br />

Esperará que tecleemos algo y lo pondrá <strong>en</strong> variable.<br />

También podemos hacer un programa <strong>en</strong> un archivo y ejecutarlo:<br />

print "Hola\n"<br />

print "Escribe tu año de nacimi<strong>en</strong>to\n"<br />

nacimi<strong>en</strong>to=read()<br />

edad=2003-nacimi<strong>en</strong>to<br />

print edad<br />

print " años\n"<br />

halt<br />

Y lo ejecutamos con bc -q archivo.bc (el -q es para que no muestre el Copyright) estaremos<br />

preguntando el año nacimi<strong>en</strong>to y mostrando la edad.<br />

Ahora un ejemplo defini<strong>en</strong>do una función, pasándole un parámetro y retornándolo. Veremos que es<br />

totalm<strong>en</strong>te intuitivo:<br />

define mayor_edad(edad) {<br />

if (edad = 18)<br />

return 1<br />

}<br />

print "Dí tus edad\n"<br />

edad=read()<br />

if (mayor_edad(edad))<br />

print "Eres mayor de edad\n"<br />

if (!mayor_edad(edad))<br />

print "Eres m<strong>en</strong>or de edad\n"<br />

halt<br />

Un último ejemplo, con un for:<br />

for (i=0;i<br />

Observemos <strong>en</strong> la , para separar la variable y la cad<strong>en</strong>a <strong>en</strong> el print.<br />

Para salir<br />

halt<br />

Otra forma muy útil <strong>en</strong> los scripts es:<br />

resultado=$(echo "scale=3;2/3" | bc)


Operaciones lógicas y de comparación<br />

test<br />

Para usar if podemos usar un nuevo elem<strong>en</strong>to, los corchetes que evalúan las<br />

condiciones, esto esta basado directam<strong>en</strong>te <strong>en</strong> test. Y éste nos sirve para comparar<br />

variables.<br />

Por ejemplo:<br />

-lt M<strong>en</strong>or que<br />

-eq Igual que<br />

-gt Mayor que<br />

-le M<strong>en</strong>or o igual que<br />

-ge Mayor o igual que<br />

-ne No coincid<strong>en</strong><br />

-a Operador lógico and<br />

-o Operador lógico or<br />

!= Distinto<br />

Sintáxis:<br />

exp1 operador exp2<br />

Uso de test:<br />

test 8 -lt 9<br />

Usando variables <strong>en</strong> test:<br />

variable1=5<br />

variable2=3<br />

test $variable1 -gt $variable2<br />

Otra forma muy útil de uso de test (si 3 es m<strong>en</strong>or que 5):<br />

[ 3 -lt 5 ]<br />

O (si $HACER es distinto de 1):<br />

[ $HACER != 1 ]<br />

Ejemplo:<br />

#!/bin/bash<br />

variable1=5<br />

variable2=3<br />

[ $variable1 -lt $variable2 ]<br />

echo $?<br />

Aqui hemos evaluado dos variables para ver si la variable1 era m<strong>en</strong>or que la<br />

variable2 y para ver el resultado hemos acudido a la “variable de retorno”, que


nos mostrara 0 o 1.<br />

Cuando necesitamos utilizar la negación, debemos usar el signo !<br />

Ejemplo:<br />

if [ ! -x $FILE ]<br />

th<strong>en</strong><br />

chmod +x $FILE<br />

else<br />

echo "$FILE es ejecutable"<br />

fi<br />

Si el archivo no es ejecutable, le damos permiso de ejecución, sino, imprimimos el<br />

m<strong>en</strong>saje por pantalla<br />

Interacción con el usuario<br />

Muchos programas no serían factibles si no tuviéramos algún mecanismo para<br />

interactuar con el usuario, ya sea un simple "Presione Enter para continuar" o<br />

algo más sofisticado, como una lista de opciones de las cuales escoger.<br />

Cuando el programa está escrito <strong>en</strong> shell, es muy s<strong>en</strong>cillo lograr ambas cosas,<br />

utilizando dos herrami<strong>en</strong>tas: read y dialog.<br />

read<br />

El comando read es muy s<strong>en</strong>cillo. Le indicamos que pida el valor de una variable al<br />

usuario, el usuario escribe una línea de texto (es decir, cualquier cosa hasta que<br />

presione <strong>en</strong>ter), y la variable toma el valor que el usuario ingresó.<br />

Ejemplo:<br />

[usuario@localhost]$ read V<br />

Hola mundo!<br />

[usuario@localhost]$ echo $V<br />

Hola mundo!<br />

[usuario@localhost]$<br />

Si deseamos sólo un "Presione <strong>en</strong>ter para continuar" es exactam<strong>en</strong>te lo mismo,<br />

simplem<strong>en</strong>te ignoramos el valor de la variable :-)<br />

dialog<br />

Dialog es un programa que crea una "interfaz" para que el usuario interactúe, y<br />

<strong>en</strong>trega por la salida estándar el resultado de la acción del usuario, variable $?.<br />

Puede producir preguntas si/no, m<strong>en</strong>ú, lista, cal<strong>en</strong>dario, barra de progreso,<br />

diálogo de contraseña, cuadro de texto, cuadro de m<strong>en</strong>saje, etc. Recom<strong>en</strong>damos leer<br />

la docum<strong>en</strong>tación del manual (man dialog) o ejecutar<br />

dialog --help<br />

Aparte del programa "dialog", que produce una salida por consola, puede ser que


t<strong>en</strong>ga <strong>en</strong> su sistema un programa "gdialog", Xdialog o "dldialog" (dep<strong>en</strong>di<strong>en</strong>do del<br />

Linux que utilice), que son lo mismo, solo que abr<strong>en</strong> una v<strong>en</strong>tana gráfica, por X11,<br />

para el diálogo.<br />

Sintaxis:<br />

dialog { --opciones específicas }<br />

Ejemplo 1 (Diálogo "yesno"):<br />

[usuario@localhost]$ dialog --yesno "Desea salir?" 6 30<br />

Produce esto:<br />

Los argum<strong>en</strong>tos 6 y 30 correspond<strong>en</strong> a la altura y ancho, respectivam<strong>en</strong>te, del<br />

cuadro. En su versión X11, sería:<br />

[usuario@localhost]$ gdialog --yesno "Desea salir?"<br />

Y se vería así:


Ejemplo 2 (Diálogo "inputbox"):<br />

[usuario@localhost]$ dialog --inputbox "Ingrese su nombre" 9 30 Juan<br />

Note que agregamos el argum<strong>en</strong>to "Juan", que será el valor predeterminado para este<br />

inputbox:<br />

O también:<br />

[usuario@localhost]$ gdialog --inputbox "Ingrese su nombre"<br />

Produce esto:<br />

El caso del "inputbox" suele t<strong>en</strong>er aparejado la necesidad de asignar ese valor<br />

ingresado a una variable. Para hacer eso t<strong>en</strong>dremos que usar la sigui<strong>en</strong>te sintáxis:<br />

VARIABLE=`gdialog --inputbox "Ingrese su nombre" 2>&1`<br />

Note que pusimos todo el comando <strong>en</strong>tre comillas invertidas para que reemplace el<br />

mismo por el valor que el comando repres<strong>en</strong>ta después de ejecutarse.


El 2>&1 es un truco que permite redirigir la STDERR hacia la STDOUT, ya que el<br />

valor ingresado sale por la salida de error <strong>en</strong> vez de la estándar.<br />

Ejemplo 3 (Diálogo "msgbox"):<br />

[usuario@localhost]$ dialog --msgbox "Esto es muy bu<strong>en</strong>o para m<strong>en</strong>sajes" 5 50<br />

Produce esto:<br />

O también:<br />

[usuario@localhost]$ gdialog --msgbox "Esto es muy bu<strong>en</strong>o para mostrar m<strong>en</strong>sajes<br />

largos o de advert<strong>en</strong>cia"<br />

Produce esto:<br />

Ejercicio 1<br />

Descompresión Automática de Archivos


Se debe ingresar el nombre de un archivo por la línea de comandos, y el script<br />

debe reconocer con qué herrami<strong>en</strong>ta está comprimida y proceder a descomprimirlo. Si<br />

el archivo no está comprimido, el script deberá devolver un m<strong>en</strong>saje de error.<br />

TIP: utilizar el programa "file"<br />

Resolución<br />

#!/bin/bash<br />

#<br />

# Decompresor intelig<strong>en</strong>te<br />

if [ -z $1 ]<br />

th<strong>en</strong><br />

#<br />

# Si no hay argum<strong>en</strong>to salimos del script con error "1!<br />

#<br />

echo "Debe ingresar el nombre del archivo"<br />

exit 1<br />

else<br />

ARCHIVO=$1<br />

fi<br />

TIPO=`file $ARCHIVO`<br />

#<br />

# Verificamos el tipo de archivo<br />

# Salida del comando file:<br />

#<br />

# Para GZIP<br />

# file ejemplo.gz<br />

# ejemplo.gz: gzip compressed data, was "ejemplo",from Unix<br />

#<br />

# Para BZIP2<br />

# file ejemplo.bz2<br />

# ejemplo.bz2: bzip2 compressed data, block size =900k<br />

case $TIPO in<br />

"${ARCHIVO}: bzip2"*)<br />

bunzip2 $ARCHIVO<br />

;;<br />

"${ARCHIVO}: gzip"*)<br />

gunzip $ARCHIVO<br />

;;<br />

*)<br />

echo "No esta comprimido"<br />

;;<br />

esac<br />

exit 0<br />

Ejercicio 2<br />

Listado del Directorio Home<br />

Se debe realizar un listado recursivo del directorio personal, y guardar la<br />

información <strong>en</strong> un archivo. Luego debe comprimirse ese archivo y preguntar al<br />

usuario <strong>en</strong> qué directorio quiere guardar el archivo comprimido.


Resolución<br />

#/bin/bash<br />

# Listado del Home<br />

# Iniciamos la variable.<br />

rm -rf ./listado.txt<br />

touch ./listado.txt<br />

ARCHIVO="./listado.txt"<br />

# Listamos los archivos y los guardamos <strong>en</strong> el archivo<br />

ls -1 ~ >> $ARCHIVO<br />

cat $ARCHIVO<br />

# Comprimimos el archivo como tar.gz<br />

tar -czvf listado.tar.gz $ARCHIVO<br />

COMPRIMIDO=listado.tar.gz<br />

# Preguntamos al usuario donde desea guardar ese archivo.<br />

echo "Por favor, ingrese el PATH donde desea almac<strong>en</strong>ar $COMPRIMIDO."<br />

read PATH<br />

echo $PATH<br />

echo $COMPRIMIDO<br />

# Guardamos el archivo donde se indico.<br />

mv $COMPRIMIDO $PATH<br />

# Se imprime donde se guardo el archivo.<br />

echo "Se guardo $COMPRIMIDO <strong>en</strong> $PATH"<br />

exit 0<br />

Ejercicio 3<br />

Ralización de un backup diario<br />

Se debe archivar como "tarball" (archivo .tar.gz) todos los archivos del<br />

directorio personal. Esto se debe hacer grabando un CR regrabable.<br />

Resolución 1<br />

#!/bin/bash<br />

#<br />

# Se limpia la pantalla para t<strong>en</strong>er una salida más prolija.<br />

clear<br />

# Se procede a desmontar el CD por si algui<strong>en</strong> olvidó hacerlo.<br />

echo "*** Desmontando CDROM ***"<br />

umount /mnt/cdrom<br />

# Se limpia nuevam<strong>en</strong>te la pantalla.<br />

clear<br />

# Se anuncia al usuario que se comi<strong>en</strong>za a borrar el CD.<br />

echo "*** Borrando CDROM ***"<br />

echo "Por favor, sea paci<strong>en</strong>te. Este proceso puede demorar hasta 20 minutos."<br />

echo " "<br />

# Se utiliza el programa cdrecord para borrar el CD.<br />

cdrecord -v -dev=ATAPI:0,0,0 -blank=fast > /dev/null<br />

# Se borra nuevam<strong>en</strong>te la pantalla.<br />

clear<br />

# Se anuncia por pantalla el comi<strong>en</strong>zo del backup del directorio.<br />

echo "*** Com<strong>en</strong>zando el backup ***"<br />

# Se crea un directorio temporal para almac<strong>en</strong>ar el backup.<br />

mkdir /tmp/backup02


# Se limpia la pantalla.<br />

clear<br />

# Se anuncia por pantalla que se comi<strong>en</strong>za a salvar el directorio personal.<br />

echo "*** Backup del directorio Personal ***"<br />

# Se comprime el directorio personal.<br />

tar -cvzf /tmp/backuo02/home.tar.gz ~/ > /dev/null<br />

# Se limpia la pantalla.<br />

clear<br />

# Se anuncia por pantalla que se realiza el ISO a grabar.<br />

echo "*** Creando archivo de Resguardo ***"<br />

# Se crea la imág<strong>en</strong> ISO.<br />

mkisofs -r -J -o backup02.iso backup02/ > /dev/null<br />

# Se borra la pantalla.<br />

clear<br />

# Se anuncia el comiezo de la grabación del CD.<br />

echo "*** Com<strong>en</strong>zando la grabacion del CDROM ***"<br />

echo "Por favor, sea paci<strong>en</strong>te. Este proceso puede tardar hasta 30 minutos."<br />

echo " "<br />

# Se comi<strong>en</strong>za a grabar el CD con cdrecord.<br />

cdrecord -v speed=4 dev=ATAPI:0,0,0 -data backup02.iso > /dev/null<br />

# Se anuncia <strong>en</strong> pantalla el borrado de los archivos auxiliares.<br />

echo "*** Limpiando archivos extras ***"<br />

rm -Rf /tmp/backup02.iso > /dev/null<br />

rm -Rf /tmp/backup02 > /dev/null<br />

# Se desmonta el CD.<br />

umount /mnt/cdrom<br />

# Se limpia la pantalla.<br />

clear<br />

# Se anuncia que el proceso finalizó con éxito.<br />

echo "*** Se realizo el backup con exito ***"<br />

exit 0<br />

Resolución 2 (backup por SAMBA)<br />

#!/bin/bash<br />

# Se limpia la pantalla para t<strong>en</strong>er una salida más prolija.<br />

clear<br />

# Se procede a desmontar el CD por si algui<strong>en</strong> olvidó hacerlo.<br />

echo "*** Desmontando CDROM ***"<br />

umount /mnt/cdrom<br />

# Se limpia nuevam<strong>en</strong>te la pantalla.<br />

clear<br />

# Se monta por red el CD de un cli<strong>en</strong>te windows.<br />

smbmount //pc3/d /mnt/cdrom -o username=usuario,password=contraseña<br />

# Se borra nuevam<strong>en</strong>te la pantalla.<br />

clear<br />

# Se anuncia por pantalla el comi<strong>en</strong>zo del backup del directorio.<br />

echo "*** Backup del directorio Personal ***"<br />

# Se comprime el directorio personal.<br />

tar -cvzf /mnt/cdrom/home.tar.gz ~/ > /dev/null<br />

# Se desmonta el CD.<br />

umount /mnt/cdrom<br />

# Se limpia la pantalla.<br />

clear<br />

# Se anuncia que el proceso finalizó con éxito.<br />

echo "*** Se realizo el backup con exito ***"<br />

exit 0

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!