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