|
Autor:
rh3nt0n
Capitulo cuarto.
En este cuarto capitulo trataremos de lleno la base de la programación en
shell-script, para que os sirva como punto de partida en la
elaboración de vuestros
propios shell-script
Trataremos el paso de parámetros o variables de captura, las variables autodefinidas
por la shell, comandos de captura de variables, comandos para operaciones
aritméticas,
condicionales simples, condicionales múltiples, ciclos o 'loops', iteración, el uso de
funciones, y captura de señales.
Dada la dificultad que conlleva el explicar cada comando con las posibles variantes
con las que se puede aplicar, explicare con ejemplos genéricos, los cuales
podréis
ir copiando y pegando en la terminal para ver su forma de funcionar y poder practicar
con ellos para un mejor entendimiento de estos. Consideraciones a tener en cuenta
Un shell-script es un guión de comandos que la shell va ejecutando en orden. A la
shell le da igual si comentamos los comandos, o los identamos, los ejecutará por orden
igualmente, pero a nosotros en scripts lo suficientemente largos no nos da igual, es
algo básico llevar un orden a la hora de elaborarlos, ya que como comenté
anteriormente en otras ocasiones, en el momento de hacer un comando, tendremos claro
lo que queremos que haga, pero a la hora de modificar un script o intentar interpretar
lo que hace un comando dentro de este, pasado el tiempo, no lo tendremos tan claro, y
agradeceremos mucho el hecho de haber tenido en cuenta esto.
Para comentar el código, ya vimos anteriormente el uso del caracter '#' almohadilla
el cual se puede utilizar antes de el comando a comentar o incluso en
líneas que
efectúen el comando propiamente dicho de este modo :
#!/bin/bash
# Ejemplo de comentado de scripts
echo "hola mundo" # este comando imprime el texto entre comillas en pantalla
Identación del código
La identación del código es algo extendido y normal en todos los lenguajes de
programación. Es un buen modo de ordenar de una forma visual el
código, para poder ver
a simple vista donde acaba una orden y empieza otra, la cual a su vez se ejecuta o
no dentro de otra orden o condición.
Esto lo entenderemos mejor de una forma visual, del mismo modo que se identan
los programas:
inicio comando 1
>>>>>>>>>inicio comando 2
>>>>>>>>>>>>>>>>>>inicio comando 3
>>>>>>>>>>>>>>>>>>fin comando 3
>>>>>>>>>fin comando 2
fin comando 1
Como se puede ver, el comando 3 empieza y acaba dentro de el comando 2 el cual
empieza y termina dentro del comando 1. Paso o captura de
parámetros o argumentos.
Como bien sabemos, en un script podemos incorporar cientos de comandos, pero estos
necesitan de argumentos para poder funcionarán shell-script que use siempre los mismos
parámetros, nos servirá una vez o dos.. pero lo realmente útil es que podamos
incorporar a nuestro script distintos argumentos para que funcione
según nos interese
en cada momento. Estos parámetros se traducen en forma de variables dentro de nuestro
script las cuales modificamos nosotros añadiendo o pasándoselas en el momento de
lanzarlo lo llamaremos forma 'estática', o haciendo que nos las pida en un momento
determinado de su ejecución, la cual llamaremos forma 'dinámica'.
Esto lo entendermos mejor, como siempre con un ejemplo:
#!/bin/bash
#Paso de argumentos de forma 'estatica'.
echo "primera opción $1"
echo "segunda opción $2"
echo "tercera opción $3"
En el ejemplo anterior al ejecutar el script tendríamos que pasarle el valor de las
variables $1, $2 y $3, en el momento de lanzar el script, para que este las tome en
consideración.
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script2 primera segunda tercera
primera opción primera
segunda opción segunda
tercera opción tercera
rh3nt0n@rh3nt0n-laptop:~/scripts$
Como vemos en su ejecución, las variables $1,$2 y $3 la shell las coge de la
línea
al lanzar este, y las traduce por orden dentro del script según se las ha llamado.
Estas variables pueden ser cadenas de texto (entrecomilladas),
números, ficheros o
rutas de directorios. Dependiendo de el tipo de argumento que necesite el comando que
las requiera.
El paso de argumentos esta limitado a 9 pero este inconveniente se subsana con el
comando 'shift' el cual explicare un poco mas adelante ya que es necesario que
antes conozcáis las variables autodefinidas por la shell para shell-script.
Variables autodefinidas por shell-script
$# ---- Esta variable contiene el numero de argumentos que hemos pasado al script.
$0 ---- Esta variable contiene el nombre de el shell-script que se ejecuta.
$* ---- Esta variable muestra una cadena con los parámetros que hemos pasado al
script.
$? ---- Esta variable contiene la salida del comando anterior donde se encuentre
dentro de el script.
Esto lo veremos mas claro añadiendo estas variables a nuestro script anterior
#!/bin/bash
#Paso de argumentos de forma 'estática'.
echo "primera opción $1"
echo "segunda opción $2"
echo "tercera opción $3"
#Variables autodefinidas
echo "se ejecuta $0"
echo "tengo $# argumentos"
echo "los cuales han sido $*"
cp #este comando necesita parámetros, por lo tanto lanzara un error que $? capturara
echo "salida de error: $?"
Al ejecutar nuestro script, obtendremos la siguiente salida:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script2a primera segunda tercera
primera opción primera
segunda opción segunda
tercera opción tercera
se ejecuta script2a
tengo 3 argumentos
los cuales han sido primera segunda tercera
cp: falta un fichero como argumento
Pruebe `cp --help' para más información.
salida de error: 1
rh3nt0n@rh3nt0n-laptop:~/scripts$
Como se puede apreciar las variables autodefinidas del script toman el valor
de los parámetros y las circunstancias en las que se ejecuta el script, variando
si estas circunstancias varían. Comando 'shift'
Este comando hace posible que podamos una vez usada una variable, eliminarla y poder
usar ese valor de variable para otro argumento, esto como es habitual lo veremos mejor
con un ejemplo:
#!/bin/bash
#uso del comando shift
echo "primera opción $1"
shift
echo "segunda opción $1"
shift
echo "tercera opción $1"
Como podremos apreciar en la ejecución de este script, el comando shift nos permite
usar una misma variable, para distintos argumentos:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script2b primera segunda tercera
primera opción primera
segunda opción segunda
tercera opción tercera
rh3nt0n@rh3nt0n-laptop:~/scripts$
Como se puede observar obtenemos la misma salida que en el primer script pero sin
la necesidad de dar un valor a cada argumento. Pase o captura de
parámetros de forma 'dinámica'.
Si en un momento dado de la ejecución de nuestro script, necesitamos de la
introducción de algún parámetro de forma, por llamarlo de alguna manera, 'en caliente', mientras se ejecuta el script, tenemos la opción de usar el comando 'read'.
Comando 'read'
Durante la ejecución de un script, si este se encuentra con el comando read seguido
de un nombre de variable, la ejecución se detendrá y nos mostrara el cursor
parpadeando en espera de que introduzcamos un parámetro, que a continuación la shell
almacenara asignándolo como valor de el nombre de variable en cuestión.
Ejemplo:
#!/bin/bash
#uso del comando read
echo "Cual es tu nombre?"
read nombre
echo "Hola $nombre"
Si hasta ahora hemos sido un poco avispados, nos habremos dado
cuenta, de que
para asignar un nombre a una variable desde read, no se usa el signo de '$'
,se usa solo en el momento de usar dicha variable.
Veamos la ejecución del script:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script3
Cual es tu nombre?
rh3nt0n <------------ aqui tipeamos el valor de la variable nombre.
Hola rh3nt0n <-------- aqui toma el valor tipeado y lo muestra por pantalla
rh3nt0n@rh3nt0n-laptop:~/scripts$
Se pueden asignar varias variables en un mismo read, así como pedir varios
argumentos con varios read.
Ejemplo:
#!/bin/bash
#uso del comando read con varios parámetros y varios read
echo "Cual es tu nombre?"
read nombre
echo "Cuales son tus apellidos?"
read apellido1 apellido2
sleep 5 # dormimos la terminal 5 segundos
echo " Tu segundo apellido es $apellido2 "
echo " Tu nombre completo es $nombre $apellido1 $apellido2"
echo " Hola $nombre"
Como veremos en la salida podemos llamar a las variables introducidas en el orden
en que queramos. Solo he usado el comando sleep para que podáis apreciar la salida de
el script diferenciada de la entrada de parámetros.
La salida seria la siguiente:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script4
Cual es tu nombre?
pingüino
Cuales son tus apellidos?
unix linux
Tu segundo apellido es linux
Tu nombre completo es pingüino unix linux
Hola pingüino
rh3nt0n@rh3nt0n-laptop:~/scripts$
Comando para operaciones aritméticas
comando 'expr'. Este comando suele usarse con asiduidad dentro de
condicionales tanto simples como múltiples que explicare mas adelante, o para
simplemente hacer operaciones aritméticas. Necesita como mínimo tres argumentos,
dos operandos y un operador.
Los operadores son los típicos de operaciones aritméticas :
suma ---------- '+'
resta --------- '-'
multiplicación- '*'Este símbolo hay que escaparlo '\*' dada su condición de
carácter especial.
división------- '/'
modulo--------- '%' el modulo no es mas que el resto de una división, el cual suele
ser el divisor menos uno.
Ejemplo de modulo: 100 % 5 ------> el modulo 5 de 100 sería de 0 a 4.Esto nos
puede servir a la hora de generar un numero aleatorio, reducirlo a la cantidad que
deseemos, Se entenderá mas adelante con algunos ejemplos.
Sintaxis: expr [operando1] operador [operando2]
Ejemplo de expr:
#!/bin/bash
#Ejemplo de expr (el cuadrado de un numero)
echo "Dame un numero."
read numero
resultado=`expr $numero \* $numero` # declaramos la variable resultado, como resultado
de expr
echo "El resultado de el cuadrado de $numero es $resultado"
La salida del script seria la siguiente:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script5
Dame un numero.
6
El resultado de el cuadrado de 6 es 36
rh3nt0n@rh3nt0n-laptop:~/scripts$
Como se puede observar read pide la variable numero, y expr se encarga de dar
como valor a la variable resultado, la operación que realiza con la variable numero, la cual en este caso no es mas que una multiplicación por si
misma. Como se puede
también observar 'escapamos' el carácter asterisco '\*' para que la shell no lo tome
como metacarácter. Evaluar cadenas
Para evaluar cadenas, ya sean cadenas de texto, ficheros, o
números, tenemos el
comando 'test' el cual nos permite de una forma rápida y fácil comparar o comprobar
cualidades o valores de las cadenas evaluadas para poder a grosso modo obtener un
resultado positivo o negativo que haga actuar a tal o cual comando de uno u otro
modo.
Comando 'test'. Este comando para que no cause confusión desde el principio
se suele abreviar usando solo corchetes [cadena valor cadena ] y suprimiendo el
propio comando 'test', dentro de un 'if', 'case', 'until', 'for' etc ...
(que veremos mas adelante) o simplemente para definir una variable,
variable=`[ $1 != $2 ]`
Como veo que me enredo mucho, veamos un ejemplo con test, con y sin comando.
Un sencillo ejemplo de 'test'para ver su sintaxis:
#!/bin/bash
# ejemplo de test
test $1 = $2 # necesitamos dos argumentos al lanzar el script
echo $? #si 'echo' devuelve un 0 es que el comando test es verdadero.
Si lo ejecutamos introduciendo dos valores iguales como argumentos, el resultado
de la comparación será verdadero, ya que evaluamos si $1 es igual '=' a $2, por
lo tanto 'echo' imprimirá un 0 en la pantalla:
rh3nt0n@rh3nt0n-laptop:~$ bash script6 uno uno
0
rh3nt0n@rh3nt0n-laptop:~$
En caso de que introduzcamos dos argumentos distintos, la comparación no será
verdadera, y por lo tanto nos devolverá un 1:
rh3nt0n@rh3nt0n-laptop:~$ bash script6 paquito paquita
1
rh3nt0n@rh3nt0n-laptop:~$
Ahora probemos a editar el anterior script de la siguiente manera, y lo ejecutamos
del mismo modo que el anterior:
#!/bin/bash
# ejemplo de test con corchetes
[ $1 = $2 ] # necesitamos dos argumentos al lanzar el script
echo $? #si 'echo' devuelve un 0 es que el comando test es verdadero.
Una vez ejecutado el script, nos daremos cuenta que es lo mismo poner los corchetes
que la palabra test. Como dijimos anteriormente, el comando test sirve para evaluar ficheros, cadenas de
texto, y números, pero estos no se evalúan de la misma forma ya que evidentemente no
son argumentos del mismo tipo, y cada uno se trata de forma diferente:
Modos de evaluar con 'test'.
1º Evaluando ficheros.
Los ficheros se pueden avaluar con estos parámetros:
-f-----------indica si el fichero existe.0 si es verdadero y 1 si es falso.
-s-----------indica si el fichero existe y no esta vacio.0 si verdad, 1 si falso.
-r-----------indica si tiene permiso de lectura.0 verdad, 1 falso.
-w-----------indica si tiene permiso de escrituta.0 verdad, 1 falso.
-x-----------indica si tiene permiso de ejecución.0 verdad, 1 faslo.
-d-----------indica si es directorio. 0 verdad, 1 falso.
Estos parámetros se pueden unir usando los enlazadores :
-a-----------and, 'y'.
-o-----------or, 'o'.
!------------not, no.
Veamos un ejemplo de evaluación de ficheros:
#!/bin/bash
# evaluación de ficheros con test.
[ -f $1 ] # al lanzar el script damos ruta relativa o absoluta del fichero.
echo $? #mostrara 0 si exite y 1 si no existe
Probemos con uno de nuestros scripts:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script7 script1
0
rh3nt0n@rh3nt0n-laptop:~/scripts$
Podemos comprobar que existe ya que la evaluación nos retorna un 0.
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script7 script10
1
rh3nt0n@rh3nt0n-laptop:~/scripts$
Podemos comprobar que no existe ya que test nos retorna un uno.
También podemos usar 'read' para introducir dinámicamente el fichero a evaluar. 2º Evaluando cadenas de texto.
Para evaluar cadenas de texto tenemos los parámetros:
parámetros:
'=' ---------- igual
'!='---------- distinto Ejemplo:
#!/bin/bash
# evaluación de ficheros con test.
[ $1 != $2 ] # al lanzar el script damos dos cadenas de texto como argumento
echo $? #mostrara 0 si distinto y 1 si si igual
Si ejecutamos el script, nos dará en función de los argumentos una salida u otra.
números aleatorios:
Antes de nada, explicare como se genera un numero aleatorio usando la variable
$RANDOM.
La variable $RANDOM genera un numero aleatorio de entre 1 y 32000, podemos necesitar
conseguir un numero aleatorio para multitud de funciones, a mi por ejemplo se me ocurre
una, los números de la primitiva, pero hay un problema, nos sobran muchos
números
ya que la primitiva solo tiene 48, para solucionar el problema utilizaremos la
expresión '%' modulo, la cual nos limita el numero aleatorio a el modulo que elijamos
de este, en este caso será 49.
Lo mejor es un ejemplo:
#!/bin/bash
# aleatorio con random 'primitiva'
alea=`expr $RANDOM % 49` # generamos un numero
aleatorio1=`expr $alea + 1`# nos aseguramos que no sea 0 sumándole 1
alea=`expr $RANDOM % 49` # el segundo ..
aleatorio2=`expr $alea + 1`
alea=`expr $RANDOM % 49`
aleatorio3=`expr $alea + 1`
alea=`expr $RANDOM % 49`
aleatorio4=`expr $alea + 1`
alea=`expr $RANDOM % 49`
aleatorio5=`expr $alea + 1`
alea=`expr $RANDOM % 49`
aleatorio6=`expr $alea + 1`
echo "Copia estos numeros:"
echo " $aleatorio1 - $aleatorio2 - $aleatorio3 " # imprimimos los tres primeros
echo " $aleatorio4 - $aleatorio5 - $aleatorio6 " # imprimimos los otros tres
La salida seria algo parecido a esto:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash aleatorio
Copia estos numeros:
24 - 2 - 29
6 - 33 - 11
rh3nt0n@rh3nt0n-laptop:~/scripts$
Por supuesto hay mas métodos para generar números aleatorios, pero me pareció la
forma mas rápida y sencilla de que vierais un ejemplo, espero que
halláis captado la
idea.
Sigamos con text. 3º Evaluando números
Pensareis que con las opciones anteriores de evaluación de cadenas de texto,
también se pueden evaluar números, y en cierto modo si se puede, pero hay que tener
algo en cuenta :
[ 04 = 4 ]
Si nos damos cuenta, esa evaluación nos devolvería '1', ya que el '='
evalúa si 04 es
igual a 4, y como cadena de texto, no lo es.
Por lo tanto, si lo que queremos es evaluar números, tenemos las siguientes opciones
o parámetros:
-lt --------- menor que ...
-le --------- menor o igual
-gt --------- mayor que ...
-ge --------- mayor o igual
-eq --------- igual
-ne --------- no igual
Visto lo cual haremos un script para adivinar un numero aleatorio, en el cual nos
basaremos para ir mejorándolo y para así entender lo que viene a continuación:
condicional simple.
#!/bin/bash
# adivinador con evaluación numérica
echo "Adivina mi numero"
read adiv
aleatorio=`date +%S` #creamos un numero aleatorio en segundos de 0 a 59
aleatorio=`expr $aleatorio % 5` # lo reducimos a su modulo 5 (de 0 a 4)
# si nos damos cuenta hemos sobrescrito la variable $aleatorio
# no hay problema en esto ...
[ $aleatorio -eq $adiv ] # evaluamos si el numero que hemos introducido es igual
a el aleatorio
echo $? # nos imprime si lo es o no: 0 si, 1 no .
Ejecutad el script:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash adivinador
Adivina mi numero:
3
0
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash adivinador
Adivina mi numero:
2
1
rh3nt0n@rh3nt0n-laptop:~/scripts$
Como se puede apreciar, en la primera ejecución he tipeado el numero 3, y he
acertado, por consiguiente la salida de el comando test es 0.
Por contra, en la segunda ejecución, he tipeado 2, y he fallado, por consiguiente
la salida ha sido un 1.
Bueno después de todo esto, espero que halla quedado claro lo que significa un 0
y lo que significa un 1 en la salida de de un test...sigamos
Condicional simple.
Cuando hablamos de condicional simple, básicamente hablamos de el uso de el comando
'if', el cual nos permite usar el 'test' para que dependiendo de la salida de
este, nuestro script haga una cosa u otra.. veamos un ejemplo con el anterior script:
#!/bin/bash
# adivinador mejorado con if
echo "Adivina mi numero:"
read adiv
aleatorio=`date +%S` #creamos un numero aleatorio en segundos de 0 a 59
aleatorio=`expr $aleatorio % 5` # lo reducimos a su modulo 5 (de 0 a 4)
# si nos damos cuenta hemos sobrescrito la variable $aleatorio
# no hay problema en esto ...
if [ $aleatorio -eq $adiv ] ; # evaluamos si el numero que hemos introducido es igual
a el aleatorio
then # si es igual pasamos a el echo de la siguiente línea
echo "has acertado!!"
else # si no es igual pasamos a el echo de mas abajo
echo "has errado!!"
fi
Si lo ejecutamos:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash adivinador2
Adivina mi numero:
3
has errado!!
rh3nt0n@rh3nt0n-laptop:~/scripts$
Podemos ver que la principal diferencia es que la salida de test nos redirige el
camino a tomar por el script hacia un comando u otro, según sea la
salida de este falsa o verdadera.
sintaxis de comando 'if':
if [ evaluación ] ;
----then
---------paso a tomar si verdadero
----else
---------paso a tomar si falso
fi
Como podréis comprobar, este comando es de los que hay que identar para una mayor
comprensión de el a la hora de comprenderlo cuando lo miremos tiempo
después de
hacerlo.
Respecto a su funcionamiento solo añadir, que en caso de que no se cumpla la
condición evaluada, no es estrictamente necesario usar 'else', con lo cual la
opción 'else' es opcional, si lo que nos interesa es una salida verdadera de la
evaluación..
Otro ejemplo de 'if' pero esta vez evaluando ficheros:
#!/bin/bash
####################################
# Este script evalua dos ficheros dados de forma estatica#
# diciendonos cual es mayor en tamaño .###########
####################################
uno=`ls -l $1 | tr -s " " | cut -f5 -d " "` #filtramos el primer fichero
dos=`ls -l $2 | tr -s " " | cut -f5 -d " "` #filtramos el segundo fichero
if [ $uno -gt $dos ] ;
then
echo " $1 es mayor "
else
echo " $2 es mayor "
fi
Si ejecutamos nuestro script, evaluando por ejemplo dos de los script que hemos
creado hasta ahora:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash ficheromayor /home/rh3nt0n/scripts/script1
/home/rh3nt0n/scripts/script7
/home/rh3nt0n/scripts/script7 es mayor
rh3nt0n@rh3nt0n-laptop:~/scripts$
Condicional múltiple.
Para explicar el uso de esta forma de condicionar, haremos una calculadora simple
la cual necesitara de tres argumentos a añadir de forma 'estática'.
así entenderemos el como y por que de la opción de el comando 'case' para poder hacer
múltiples condiciones, sin necesidad de alargar el código con 'if' recurrentes, como
en el siguiente caso:
#!/bin/bash
# calculadora con if.
if [ $3 = "suma" ]
then
expr $1 + $2
else
if [ $3 = "resta" ]
then
expr $1 - $2
else
if [ $3 = "multi" ]
then
expr $1 \* $2
else
if [ $3 = "divi" ]
then
expr $1 / $2
else
echo "opción no valida"
fi
fi
fi
fi
Si ejecutamos la calculadora:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash calculadora 34 56 suma
90
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash calculadora 34 56 multi
1904
rh3nt0n@rh3nt0n-laptop:~/scripts$
Bien, vemos que la calculadora funciona, pero el código es demasiado extenso y
además tiene demasiados 'if', y no es necesario si usamos 'case'.
Comando 'case'.
Sintaxis:(cambiad '>' por espacios)
case variable in
>>>>>>patron1)>>>>ordenes ;;
>>>>>>patron2)>>>>ordenes ;;
>>>>>>patron3)>>>>ordenes ;;
.
.
.
>>>>>>*)>>>>>>>>ordenes ;;
esac
Veamos como ejemplo la calculadora anterior a que se reduce con 'case':
#!/bin/bash
# Calculadora con case
case $3 in
"suma")
expr $1 + $2 ;;
"resta")
expr $1 - $2 ;;
"multi")
expr $1 \* $2 ;;
"divi")
expr $1 / $2 ;;
esac
Al ejecutar nuestra nueva calculadora con la mitad de líneas gracias a case,
tenemos que case nos permite dar múltiples valores a una variable y actuar de la
forma que sea, según el valor que introduzcamos.
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash calculadora2 50 50 multi
2500
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash calculadora2 50 50 suma
100
rh3nt0n@rh3nt0n-laptop:~/scripts$
Ciclos o loops.
Los ciclos o loops, sirven para hacer que cuando se cumple una determinada
circunstancia, una orden se repita, hasta que esa circunstancia deje de cumplirse.
Para esto tenemos varios comandos que comentaremos a continuación:
Comando 'while'.'mientras'
Este comando ejecuta las ordenes que contenga, si la condición es cierta.(0).
Sintaxis:
while [ condición ]
do
#orden
#orden
.
.
.
done
Veamos un ejemplo:
#!/bin/bash
# El cuadrado de 1 a 100 con while
cont=1
while [ $cont -lt 100 ] #siempre se usa test, se evalua que $cont sea menor que 100
do
cuad=`expr $cont \* $cont` #hacemos que $cuad valga el cuadrado de $cont
echo "el cuadrado de $cont es: $cuad"
cont=`expr $cont + 1` #hacemos que $cont se vaya incrementando en uno.
done
Al ejecutarlo, veremos que while hace que se repitan de la línea 4 a la 8, hasta
que la condición $cont -lt 100, se incierta, o sea que $cont valga 100 o mas.
rh3nt0n@rh3nt0n-laptop:~$ bash script8
el cuadrado de 1 es: 1
el cuadrado de 2 es: 4
el cuadrado de 3 es: 9
el cuadrado de 4 es: 16
el cuadrado de 5 es: 25
.
.
.
el cuadrado de 94 es: 8836
el cuadrado de 95 es: 9025
el cuadrado de 96 es: 9216
el cuadrado de 97 es: 9409
el cuadrado de 98 es: 9604
el cuadrado de 99 es: 9801
rh3nt0n@rh3nt0n-laptop:~$
También tenemos la opción de el comando 'until' que hace lo mismo que while pero al
contrario, o sea su negación.
Comando 'until'.'hasta' Negación de while.
Sintaxis:
until [ condición ]
do
ordenes #misma estructura que while
done
Veamos otro ejemplo:
#!/bin/bash
# imprimimos hasta 10 con until
cont=1
until [ $cont -gt 10 ] #hasta que $cont sea mayor que 10
do
echo $cont
cont=`expr $cont + 1`
done
Al ejecutarlo veremos que el bucle funciona hasta que la variable $cont es mayor
que 10.
rh3nt0n@rh3nt0n-laptop:~$ bash script9
1
2
3
4
5
6
7
8
9
10
rh3nt0n@rh3nt0n-laptop:~$
Comando de iteración 'for'.
Este comando es muy útil para evaluar y actuar sobre elementos que estamos
pasando por parámetros.
Sintaxis:
for variable in 'lista de parámetros'
do
ordenes
done
Veamos un ejemplo basico:
#!/bin/bash
# ejemplo basico de for
for numero in $1
do
echo $numero
done
Al ejecutarlo veremos que coge los argumentos y ejecuta uno a uno el comando entre
do y done:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script10 "uno dos tres"
uno
dos
tres
rh3nt0n@rh3nt0n-laptop:~/scripts$
Continuemos con for.
Ahora veremos una forma de estructurar for condicionando directamente la variable a
introducir por parametros.
Sintaxis:
for (( 1º ; 2º ; 3º ))
do
done
1º Da un valor de inicio a la variable.
2º Condiciona la variable.
3º Incrementa la variable.
Veamos un ejemplo tonto en el que nuestro script nos dirá de un rango entre
dos números dados por parámetros la cantidad de números que hay entre ellos
y que son menores que el mayor de los introducidos, en caso de
que el primer parámetro sea mayor que el segundo se parara el script avisando del
error :
#!/bin/bash
# mas opciones de for
if [ $1 -lt $2 ]
then
numero=`expr $2 + 1`
for (( i=$1 ; i<$numero ; i++ ))
do
echo "$i es menor que $numero"
if [ $i = $2 ]
then
exit 0
fi
done
else
echo "opcion incorrecta !! la primera variable a de ser menor"
fi
Si ejecutamos el script veremos que for da el valor a la variable i, la compara con
el segundo parámetro dado, si es menor ejecuta el comando echo, y
después incrementa
el valor de i en uno, haciendo esto hasta que i es igual o mayor que el segundo
parámetro:
rh3nt0n@rh3nt0n-laptop:~$ bash prueba 44 45
44 es menor que 46
45 es menor que 46
rh3nt0n@rh3nt0n-laptop:~$
Si la primera variable es mayor que la segunda, nos lanza el error y sale:
rh3nt0n@rh3nt0n-laptop:~$ bash prueba 46 45
opcion incorrecta !! la primera variable a de ser menor
rh3nt0n@rh3nt0n-laptop:~$
Como operar con los ciclos.
Podemos interactuar con los ciclos o bucles según se comporten estos, es decir, si por ejemplo obtenemos una indeterminación dentro de un bucle, podemos hacer que
este pare y salte a la siguiente línea del script dejando el bucle, que siga con el
bucle, o que el script pare.
Para esto, podemos usar los siguientes comandos:
Comando 'break'. Si después de una indeterminación en un bucle, la shell
encuentra un break, esta lo interpreta saltando el bucle y siguiendo con la siguiente
orden después del bucle.
Comando 'continue'. continue, es un escape, con lo cual, si el bucle termina
correcta o incorrectamente, y la shell encuentra un continue, en lugar de proseguir con
el siguiente comando después del bucle, vuelve a ejecutar el bucle.
Comando 'exit'. Aunque exit no es un comando exclusivo de los bucles, también
se usa con estos, en el caso de que queramos parar la ejecución del script, si se
produce una situación determinada.
Para comprender el uso de estas ordenes, crearemos un script con un bucle que de
como resultado una indeterminación. Por ejemplo una indeterminación seria el resultado
de dividir un numero entre cero :
#!/bin/bash
# ejemplo de indeterminación
for (( i=-10 ; i<=10 ; i++ ))
do
if [ $i -ne 0 ] ; then
expr 1 \ $i
else
break # continue # exit # aqui probad con cada una de las opciones
fi
done
Ahora probemos estas opciones con un script mas útil, el siguiente ejemplo te dice
de un rango de números dados por parámetros, cuales son pares:
#!/bin/bash
# ejemplo con continue break y exit
if [ $# -ne 2 ] ; then
echo "necesito dos argumentos"
exit 1
fi
if [ $1 -gt $2 ] ; then
echo "$1 no puede ser mayor que $2"
exit 2
fi
for (( i=$1 ; i<$2 ; i++ ))
do
mod=`expr $i % 2`
if [ $mod -ne 0 ] ; then
continue # aqui probad primero segun esta y despues con break y exit
fi
echo " $i es par !!"
done
Al ejecutarlo según esta, la salida será:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script13 4 9
4 es par !!
6 es par !!
8 es par !!
rh3nt0n@rh3nt0n-laptop:~/scripts$
Si cambiamos la línea que contiene el continue, por break o exit, la salida
será
como esta, ya que el bucle con estas dos opciones quedara inutilizado:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script13 4 9
4 es par !!
rh3nt0n@rh3nt0n-laptop:~/scripts$
Menús selectivos en shell-script.
En shell-script, podemos confeccionar menús con los cuales elegir opciones a
ejecutar con solo pulsar una tecla, para esto tenemos el comando 'select', el cual
siempre debe de ir acompañado de el comando 'case'.
Sintaxis:
select i in lista de opciones
do
case
esac
done
Veamos un ejemplo:
#!/bin/bash
# ejemplo de select
select i in managed monitor cualquiera_orden salida
do
case $i in
"managed") echo "aquí podríamos poner la configuración de nuestra interfaz de red en
modo managed";;
"monitor") echo "aquí podríamos poner la configuración de nuestra interfaz de red en
modo monitor";;
"cualquiera_orden") echo "aquí podríamos hacer lo que nos diera la gana..";;
"salida") break;;
*) exit;; # esta opción hace que con cualquier opción que tecleemos invalida, el
script pare.
esac
done
Al ejecutarlo tendremos:
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script11
1) managed 3) cualquiera_orden
2) monitor 4) salida
#? 1
aquí podríamos poner la configuración de nuestra interfaz de red en modo managed
#? 3
aquí podríamos hacer lo que nos diera la gana..
#? 4
rh3nt0n@rh3nt0n-laptop:~/scripts$
Uso de funciones
Una función es un trozo de código que se utilizara con frecuencia en un script,
y que solo varia en una variable.
Sintaxis:
nombre_funcion() {
código a ejecutar en la función
}
Veamos un ejemplo:
#!/bin/bash
# determina par e impar de los números que introduzcamos
dinámicamente
determinaPar() { # aquí empieza la función
num=`expr $a % 2`
if [ $num -eq 1 ];then
echo "impar ; $a"
else
echo "par: $a"
fi
} # aquí termina la función
echo "Dame tres números"
read a1
read a2
read a3
export a=$a1
determinaPar
export a=$a2
determinaPar
export a=$a3
determinaPar
Si lo ejecutamos veremos que a cada variable introducida se le aplica la función,
lo cual ahorra muchas líneas de código ya que sin usar la función,
tendríamos que
repetir continuamente el código que contiene esta, para cada variable, con lo que
esto conllevaría.
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script12
Dame tres numeros
700
75
12346
par: 700
impar: 75
par: 12346
rh3nt0n@rh3nt0n-laptop:~/scripts$
Captura de señales.
Podemos hacer que nuestro script capture señales a la shell, lanzadas desde el
teclado tipo 'crtl+c' y que la shell las ignore.
Para esto, se usa el comando 'trap'.
Comando 'trap'.Atrapa señales.
Sintaxis:
trap ordenes señal
ó:
trap señal <---- captura señal
Veamos un ejemplo:
#!/bin/bash
# Ejemplo de trap
trap mensaje 2
mensaje() {
echo "no puedes pararme ;)"
}
while [ 1 -eq 1 ] # buble infinito
do
date
sleep 1
done
Al ejecutarlo veremos que con 'ctrl+c' no podemos pararlo, podremos 'pararlo' usando
'ctrl+z', pero no podremos terminarlo hasta que no hagamos un 'kill %PID' :
rh3nt0n@rh3nt0n-laptop:~/scripts$ vi script15
rh3nt0n@rh3nt0n-laptop:~/scripts$ bash script15
sáb nov 18 23:46:52 CET 2006
sáb nov 18 23:46:53 CET 2006
no puedes pararme ;)
sáb nov 18 23:46:54 CET 2006
sáb nov 18 23:46:55 CET 2006
no puedes pararme ;)
sáb nov 18 23:46:56 CET 2006
sáb nov 18 23:46:57 CET 2006
no puedes pararme ;)
sáb nov 18 23:46:57 CET 2006
sáb nov 18 23:46:58 CET 2006
sáb nov 18 23:46:59 CET 2006
[2]+ Stopped bash script15
rh3nt0n@rh3nt0n-laptop:~/scripts$ jobs
[1]- Stopped bash script15
[2]+ Stopped bash script15
rh3nt0n@rh3nt0n-laptop:~/scripts$kill %1
rh3nt0n@rh3nt0n-laptop:~/scripts$ jobs
[1]- Terminado bash script15
[2]+ Stopped bash script15
rh3nt0n@rh3nt0n-laptop:~/scripts$ kill %2
rh3nt0n@rh3nt0n-laptop:~/scripts$ jobs
[2]+ Terminado bash script15
rh3nt0n@rh3nt0n-laptop:~/scripts$
Bueno, pues con esto ultimo hemos acabado la iniciación a la shell-script.
Por supuesto que hay mas comandos y mas funciones, pero esto es lo
básico, y solo
es un punto de partida para que podáis seguir practicando con este 'lenguaje de
programación' y profundicéis en el para que podáis sacarle el mayor partido a la shell.
También deciros que es posible que halla algún error en las explicaciones, si os dais
cuenta de alguno, espero que perdáis un par de minutos en
comunicármelo en el foro.
Gracias por leerlo y espero que os sirva de ayuda .
después de este rollo que os he soltao, os emplazo a el siguiente capitulo y espero
que no ultimo, en el que trataremos temas de configuraciones de interfaces de red, iptables, y alguna que otra sorpresa mas.
Saludos.
Autor:
rh3nt0n
|