Estructuras de Control en Shell

33
1 UNIVERSIDAD NACIONAL AUTÓNOMA DE MÉXICO FACULTAD DE CONTADURÍA Y ADMINISTRACIÓN LICENCIATURA EN INFORMÁTICA SISTEMAS OPERATIVOS MULTIUSUARIOS GONZÁLEZ GUIZAR GRISELDA SOCORRO “ESTRUCTURAS DE CONTROL EN SHELL” ZAMORANO PARTIDA RAINIER 2291 ABRIL 2011, MÉXICO D.F.

Transcript of Estructuras de Control en Shell

Page 1: Estructuras de Control en Shell

1

UNIVERSIDAD NACIONAL AUTÓNOMA DE MÉXICO

FACULTAD DE CONTADURÍA Y ADMINISTRACIÓN

LICENCIATURA EN INFORMÁTICA

SISTEMAS OPERATIVOS MULTIUSUARIOS

GONZÁLEZ GUIZAR GRISELDA SOCORRO

“ESTRUCTURAS DE CONTROL EN SHELL”

ZAMORANO PARTIDA RAINIER

2291

ABRIL 2011, MÉXICO D.F.

Page 2: Estructuras de Control en Shell

2

ÍNDICE

CARÁTULA-------------------------------------------------------------------------------------------------1

INTRODUCIÓN--------------------------------------------------------------------------------------------3

CONTENIDO-----------------------------------------------------------------------------------------------5

Programación Shell en Linux

¿Qué es Shell?

Shells disponibles en Linux

Principios de los Shell, Operación de los Shells y conceptos básicos de sintaxis--------------6

Estructuras de Control------------------------------------------------------------------------------------7

Secuencias Condicionales : IF ... FI

Control de Flujo------------------------------------------------------------------------------------------8

Estructura CASE

Lazos FOR----------------------------------------------------------------------------------------9

Bucle WHILE-------------------------------------------------------------------------------------10

Bucle UNTIL

BREAK & CONTINUE

Ciclos de Control

El ciclo While-----------------------------------------------------------------------------------11

El ciclo For--------------------------------------------------------------------------------------13

Control de Ciclos----------------------------------------------------------------------------------------14

Secuencia Condicional CASE … ESAC----------------------------------------------------------15

Bucles FOR--------------------------------------------------------------------------------------17

Bucles WHILE-----------------------------------------------------------------------------------19

Sintaxis De Las Sentencias De Control------------------------------------------------------------------20

CASE ... IN ... ESAC

IF ... THEN ... FI----------------------------------------------------------------------------------21

FOR ... DO ... DONE-----------------------------------------------------------------------------22

WHILE ... DONE---------------------------------------------------------------------------------23

UNTIL ... DONE

Estructuras Condicionales y Selectivas------------------------------------------------------------------24

Estructuras Condicionales

Estructura Selectiva-----------------------------------------------------------------------------26

Bucles----------------------------------------------------------------------------------------------------28

Bucles Genéricos

Bucles Condicionales While & Until------------------------------------------------------------30

Bucle de Selección Interactiva------------------------------------------------------------------31

CONCLUSIONES-----------------------------------------------------------------------------------------32

BIBLIOGRAFÍA--------------------------------------------------------------------------------------------33

MESOGRAFÍA

Page 3: Estructuras de Control en Shell

3

INTRODUCCIÓN

El intérprete de mandatos o "shell" es la interfaz principal entre el usuario y el

sistema, permitiéndole a aquél interactuar con los recursos de éste. El usuario

introduce sus órdenes, el intérprete las procesa y genera la salida correspondiente.

Por lo tanto, un intérprete de mandatos de Unix es tanto una interfaz de ejecución

de órdenes y utilidades, como un lenguaje de programación, que admite crear

nuevas órdenes –denominadas guiones o “shellscripts”–, utilizando combinaciones

de mandatos y estructuras lógicas de control, que cuentan con características

similares a las del sistema y que permiten que los usuarios y grupos de la máquina

cuenten con un entorno personalizado.

En Unix existen 2 familias principales de intérpretes de mandatos: los basados en el

intérprete de Bourne (BSH, KSH o BASH) y los basados en el intérprete C (CSH o

TCSH).

No es un secreto que los sistemas operativos Unix/Linux han evolucionado en los

últimos años como un sistema operativo popular. Para los programadores que han

utilizado Unix/Linux por muchos años, esto no es una sorpresa: Los sistemas

Unix/Linux proveen una plataforma eficiente y elegante para el desarrollo de

sistemas. Después de todo, esto es lo que Dennis Ritchie y Ken Thompson

buscaban cuando ellos desarrollaron Unix en los laboratorios Bell (a finales de los

60's).

Una de las características fuertes de los sistemas Unix/Linux es su gran colección de

programas. Más de 200 comandos básicos que se incluyen con el sistema

operativo. Estos comandos, (también conocidos como herramientas) hacen

prácticamente todo, desde contar el número de lineas en un archivo, enviar correo

electrónico, desplegar un calendario del año deseado, etc.

Pero la real fortaleza de los sistemas Unix viene no precisamente de esta gran

colección de comandos, sino también de la elegancia y facilidad con que estos

comandos pueden ser combinados para realizar funciones más sofisticadas.

Con el fin de proveer una interface consistente y fácil para que el usuario

interactuara con el sistema Unix/Linux (el kernel) se desarrolló el shell.

El shell es simplemente un programa que lee los comandos que se teclean y los

convierte en una forma más entendible para el sistema Unix/Linux. También incluye

algunas sentencias básicas de programación que permiten: tomar decisiones,

realizar ciclos y almacenar valores en variables.

Page 4: Estructuras de Control en Shell

4

El shell estándar distribuido con Unix y Linux, se deriva de la distribución de AT&T,

el cual a su vez, evoluciono de una versión originalmente escrita por Stephen

Bourne en los laboratorios Bell. Desde entonces la IEEE ha creado estándares

basados en el Bourne Shell y otros shells más recientes. La versión actual de este

estándar es "The Shell and Utilities Volume of IEEE Std 1003.1-2001", también

conocido como es estándar POSIX (Portable Operating System Unix)

Debido a que el shell ofrece un lenguaje de programación interpretado, se pueden

escribir, modificar y verificar programas rápidamente y de forma fácil.

La programación en shell es una parte fundamental de la administración de

sistemas basados en Unix, debido a la facilidad y poderío que el conjunto de

herramientas y comandos de Unix proveen para realizar la automatización de

procesos rutinarios, tales como: respaldo de archivos, captura de datos, verificación

de procesos, etc.

Page 5: Estructuras de Control en Shell

5

CONTENIDO

Programación Shell en Linux

El turno ahora es para los intérpretes de comandos de Linux y su programación,

conocida como programación shell. Aunque el intérprete de comandos es

independiente del lenguaje de programación utilizado, Linux permite crear

programas utilizando características propias de cada uno de los shell existentes.

¿cómo, no hay solo un intérprete? No; hay bastantes shells para Linux (o

intérpretes de comandos o consolas o como lo llames [de ahora en adelante shell]).

No como en Windows que tan solo tiene el intérprete de DOS (o cmd o command).

Como habrás podido deducir la programación en shell es “interpretada”, no

compilada, lo que reduce el desempeño del sistema; pero la ventaja es la facilidad

de creación y mantención.

¿Qué es Shell?

Unos dicen que es el sistema operativo, otros dicen que es una pantalla negra sin

sentido y anticuada, otros dicen que es la causa de que Linux no sea famosa entre

gente inexperta. ¿quién tiene la razón? Hagan sus apuestas!!! No, ahora en serio.

NO es el sistema operativo (el sistema operativo es el software que dirige la

computadora, habla con el hardware, carga y ejecuta programas, etc.); cuando se

ve el indicador de la computadora y se escriben comandos para ejecutar, con lo

que estamos tratando es con el shell.

Una característica interesante de Linux, es que los shells son completamente

independientes. Como usuario tenemos la libertad de elegir entre uno u otro shell.

También es posible interactuar con un shell, y escribir comandos para otro.

Shells disponibles en Linux

Piensa que el shell es un programa que está entre el usuario y el sistema operativo.

Este programa interpreta lo que el usuario le indica (en su lenguaje) para manipular

el sistema operativo.

El shell original disponible en los sistemas UNIX era el shell Bourne (“sh”). Después

dos shells que se volvieron populares fueron shell Korn (“ksh”) y el el shell C (“csh”),

cada uno con sus características propias, ventajas y desventajas.

Los shells Bourne y el C fueron reescritos, como resultado ahora tenemos el

“Bourne again shell (Shell Bourne nuevamente)” o “bash”, y el shell T (“tcsh”). Los

tres shells están disponibles en casi todas las distros de Linux. Bash es

probablemente el shell más utilizado actualmente, y es el que viene por defecto en

la mayoría de las distros.

Page 6: Estructuras de Control en Shell

6

Principios de los Shell, Operación de los Shells y conceptos básicos de sintaxis

El shell es un programa que nos permite interactuar con el sistema operativo. La

“línea de comandos” es la entrada del usuario para el shell. El shell examina la línea

de comandos, verifica que lo que se ha escrito es correcto, determina si se ha

digitado el nombre de un programa (un programa binario o compilado), y de ser

así envía dicho programa al núcleo (kernel) para su ejecución.

Todos los comandos shell utilizan el siguiente formato:

comando opcion1 opcion2 opcion3 ... opcionN argumento1 argumento2 ...

argumentoN

Esta línea se conoce como línea de comandos; que consiste en un comando y una

o más opciones (y/o argumentos). Por lo general el espacio en blanco se ignora. En

Linux los comandos son sensibles al uso de mayúsculas y minúsculas, cosa que no

pasa en Windows. El comando se termina pulsando la tecla Enter; aunque se puede

continuar el comando en una nueva línea usando backslash (\).

Comando larguisisisisisisisimo opcion1 opcion2 opcion3 ... opcionN \ argumento1

argumento2 ... argumentoN

Además es posible concatenar varios comandos, separándolos con punto y coma

(;), por ejemplo:

clear; pwd; ls

Page 7: Estructuras de Control en Shell

7

Estructuras de Control

Secuencias Condicionales : IF ... FI

La sintaxis de ésta sentencia es :

if <condicion>

then

..... comandos ....

else

..... comandos ....

Fi

(la cláusula "else" puede omitirse ; sólo se usará cuando se requiera).

La condición puede escribirse como "test <argumentos>" o con corchetes. Es

imprescindible en

este último caso , poner espacios entre los corchetes y los valores.

Posibles condiciones y su sintaxis :

if [ <variable> = <valor> ] : variable es igual a valor. Ojo con los espacios en „=„ .

if [ <variable> != <valor> ] : variable es distinta a valor.

if [ <variable -eq <valor> ] : variable es igual a valor . La variable debe contener

números. En éste caso , valen las comparaciones siguientes :

-eq : Igual (equal)

-ne : Distinto (not equal)

-ge : Mayor ó igual (Greater or equal).

-le : Menor ó igual (Less or equal).

-lt : Menor que (Less than).

-gt : Mayor que (Greater than).

if [ -f <fichero> ] : Existe <fichero>. Ojo con los espacios.

if [ -d <fichero> ] : Existe <fichero> y es un directorio.

if [ -s <fichero> ] :Existe <fichero> y tiene un tamaño mayor de cero.

if [ -x <fichero> ] : Existe <fichero> y es ejecutable.

Page 8: Estructuras de Control en Shell

8

En el campo <condición> vale escribir comandos, los cuales se ejecutarán y el valor

de la

condición dependerá de dos factores :

* Retorno 0 del comando = VERDADERO.

* Retorno != 0 del comando = FALSO.

Ejemplo de ésto último sería el siguiente programa :

if grep jose /etc/passwd

then # retorno del comando -grep- ha sido CERO

echo "Jose esta registrado como usuario"

else # retorno del comando grep NO ha sido CERO.

echo "Jose NO esta registrado como usuario"

fi

Control de Flujo

Además del if bash permite otras estructuras de control de

flujo: case, for, while y until

Estructura CASE

case valor in

patrón_1)

comandos si value = patrón_1

comandos si value = patrón_1 ;;

patrón_2)

comandos si value = patrón_2 ;;

*)

comandos por defecto ;;

esac

si valor no coincide con ningún patrón se ejecutan los comandos después

del *)

o esta entrada es opcional

patrón puede incluir comodines y usar el símbolo | como operador OR

Page 9: Estructuras de Control en Shell

9

Ejemplo:

#!/bin/bash

echo -n "Respuesta:" read RESPUESTA

case $RESPUESTA in

S* | s*)

RESPUESTA="SI";;

N* | n*)

RESPUESTA="NO ";;

*)

RESPUESTA="PUEDE";;

esac

echo $RESPUESTA

Lazos FOR

for var in lista

do

comandos

done

var toma los valores de la lista

Ejemplos

LISTA="10 9 8 7 6 5 4 3 2 1"

for var in $LISTA

do

echo $var

done

dir="/var/tmp"

for file in $dir/*.bak

do

rm -f $file

done

Sintaxis alternativa, similar a la de C

LIMIT=10

for ((a=1, b=LIMIT; a <= LIMIT; a++, b--))

do

echo "$a-$b"

done

Page 10: Estructuras de Control en Shell

10

Bucle WHILE

while comando

do

comandos

done

se ejecuta mientras que el código de salida de comando sea cierto

Ejemplo:

while [ $1 ]

do

echo $1

shift

done

Bucle UNTIL

until comando

do

comandos

done

se ejecuta hasta que el código de salida de comando sea hace cierto

Ejemplo:

until [ "$1" = ""]

do

echo $1

shift

done

BREAK & CONTINUE

Permiten salir de un lazo (break) o saltar a la siguiente iteración (continue)

break permite especificar el número de lazos de los que queremos salir

(break n)

Page 11: Estructuras de Control en Shell

11

Ejemplo con break:

# Imprime el contenido de los ficheros hasta que

# encuentra una línea en blanco

for file in $*

do

while read buf

do

if [ -z "$buf"]

then

break 2

fi

echo $buf

done < $file

done

Ciclos de Control Los dos tipos principales de ciclos son:

- el ciclo While

- el ciclo For

El ciclo while permite ejecutar un conjunto de comandos de forma repetida hasta

que una condición ocurra.

El ciclo for permite ejecutar un conjunto de comandos de forma repetida por cada

elemento en una lista.

El ciclo While

La sintaxis básica del ciclo while es:

while comando

do

sentencias

done

Donde comando es normalmente una expresión del comando test (aunque

también puede ser un comando para ejecutar).

sentencias se refiere a el cuerpo del ciclo while y contiene el código a ejecutar en

cada iteración del ciclo. Las sentencias do y done son utilizadas por el comando

while para saber en qué partes inicia y termina el ciclo.

La ejecución de un ciclo while es de la siguiente manera:

1.- se ejecuta el comando

2.- si el código de salida del comando es diferente de cero, el ciclo no se ejecuta

Page 12: Estructuras de Control en Shell

12

3.- si el código de salida del comando es cero, las sentencias del cuerpo del ciclo se

ejecutan

4.- se regresa al paso numero 1

Si tanto el comando como las sentencias son pocos o muy cortos se puede

codificar de la siguiente manera:

while command; do sentencias; done

Control de flujo

Un pequeño ejemplo que usa el ciclo while para desplegar números del cero al

nueve

x=0

while [ $x -lt 10 ]

do

echo $x

x=$((x+1))

done

Cada vez que el ciclo se ejecuta, se verifica si la comparación inicial [ $x -lt 10 ] es

verdadera, en caso de que no sea verdadera, el ciclo termina.

También se pueden crear comandos while anidados:

while comando1

do

sentencias1

while comando2

do

sentencias2

done

sentencias3

done

Como un ejemplo podríamos ejecutar este código:

x=0

while [ "$x" -lt 10 ]

do

y="$x"

while [ "$y" -ge 0 ]

do

echo -n "$y "

y=$((y - 1))

done

echo

x=$((x+1))

done

Page 13: Estructuras de Control en Shell

13

El ciclo For

A diferencia del ciclo while, el cual sale del ciclo cuando una condición es falsa, el

ciclo for opera en base a una lista de datos. El ciclo for repite un set de comandos

por cada dato en la lista.

La sintaxis básica del ciclo for es:

for variable in dato1 dato2 dato3 ... datoN

do

sentencias

done

Donde variable es el nombre de una variable y dato1 a datoN son secuencias de

caracteres o números separados por espacios. Cada vez que el ciclo for se ejecuta

el valor de cada dato en la lista es almacenado en la variable.

Lo cual significa que las veces que el ciclo for ejecutara las sentencias depende del

número de palabras, datos o sentencias especificados en la lista, por ejemplo:

Si se especificara la siguiente lista de datos en un ciclo for:

a veces no hay nada el ciclo se ejecutaría 4 veces.

Por ejemplo:

for x in 1 2 3 4 5 6 7 8

do

echo $x

done

for archivos in /directorio/*

do

cp $archivos /tmp/respaldo

chmod 777 /tmp/respaldo/$archivos

done

Control de flujo

for x in `cat /etc/hosts`

do

echo "encontre este dato >$x<"

done

o

for x in ${array[@]}

do

echo "valor: $x"

done

Page 14: Estructuras de Control en Shell

14

Control de Ciclos Cuando revisamos el comando while anteriormente, vimos que el ciclo terminaba

cuando una condición particular se cumplía.

Pero si por alguna razón la condicion nunca se cumple, el ciclo continuara para

siempre. Por ejemplo en el siguiente código:

x=0

while [ x -lt 10 ]

do

echo $x

x=$((x+1))

done

En donde en la comparación nos faltó poner meta carácter ($) en la variable x

Pero a veces es útil crear ciclos infinitos controlados por las sentencias del ciclo,

por ejemplo:

while :

do

x=$((x+1)

if [ $x -gt 100 ]; then

break;

fi

done

El operador : (dos puntos) es un comando del sistema que su valor de ejecución

siempre es 0, por lo cual es útil para crear ciclos while infinitos.

Control de flujo

O por ejemplo, para crear un Daemon:

#!/bin/sh

usuario="[email protected]"

while :

do

if [ `ps -ef | grep "sshd" | grep -v grep | wc -l` -lt 1 ]; then

# el proceso no esta corriendo!!

echo "aguas!!, el proceso sshd ya no corre" > /tmp/procdaemon.$$

mail -s"aguas!!" $usuario < /tmp/procdaemon.$$

rm /tmp/procdaemon.$$

# tratando de levantar nuevamente el proceso

/etc/rc.d/init.d/sshd stop

/etc/rc.d/init.d/sshd start

fi

sleep 300 # 5 minutos

done

Page 15: Estructuras de Control en Shell

15

Secuencia Condicional CASE … ESAC

Sintaxis :

case <variable> in

<valor> ) <comando> ( la variable es = valor , ejecuta los comandos hasta „;;‟ )

<comando>

;;

<valor> ) <comando>

<comando>

;;

* ) <comando> ( Clausula "otherwise" ó "default" : Si no se cumple alguna

<comando> de las anteriores ejecuta los comandos hasta „;;‟ )

;;

esac ( Igual que if acaba en fi , case acaba en esac )

Ejemplos: minimenu.sh

clear # borrar pantalla

echo "1.- Quien hay por ahi ?" # pintar opciones

echo "2.- Cuanto disco queda ?"

echo "3.- Nada. Salir. "

echo "Cual quieres ? : \c" # el carácter "\c" evita que el echo salte nueva línea

read opcion # "opcion" vale lo que se ha tecleado en pantalla

case "$opcion" in # IMPORTANTE : Poner la variable como "$opcion"

1) who ;; # pues si el señor pulsa <INTRO> daría error al no valer nada.

2) df;;

3) echo "Adios";;

*) echo "Opcion $opcion Es Incorrecta" ;;

Esac

# programa para paginar un fichero con mensaje al final de cada pantalla

# llamar como "mas <ficheros>"

pg -p „Pagina %d : „ -n $*

# programa para seleccionar interactivamente ficheros

# se usa dentro de una pipe como : cat `pick *` | <el comando que se quiera , tal

que lp>

Page 16: Estructuras de Control en Shell

16

for j # no tiene error! esta cosa rara permite coger todos los ficheros del

argumento

do

echo "$j ? \c" >/dev/tty

read resp

case $resp in

s*) echo $j ;; # si escribe "s" ó "si"

n*) break ;; # lo mismo esac

done </dev/tty

# programa para borrar de un directorio los ficheros mas viejos de 7 días

# llamar como "limpia.sh <directorio>"

case $# in

0) echo "Falta argumentos"

exit 1

;;

esac

cd $1 && { find . -type f -mtime +7 -exec rm -f -- {} \; ; }

# programa que saca el date en formato dia/mes/año hora:minuto:segundo

# llamar como "fecha.sh"

d=`date „+%d/%m/%y %H:%M:%S‟`

echo "FECHA Y HORA : $d"

# programa para detectar si alguien inicia sesión

# llamar como "watchfor <nombre_de_usuario>"

# Extraído del "Unix Programming Environment" de Kernighan & Pike

case $# in

0) echo "Sintaxis : watchfor usuario" ;

exit 1 ;;

esac

until who | grep "$1"

do

sleep 60

done

Page 17: Estructuras de Control en Shell

17

Bucles FOR

Sintaxis :

for <variable> in <lista>

do

<.. comandos ..>

Done

El bloque entre "for" y "done" da tantas vueltas como elementos existan en <lista>

, tomando la variable cada uno de los elementos de <lista> para cada iteración . En

esto conviene no confundirlo con los for..next existentes en los lenguajes de tipo

algol (pascal , basic ...) que varían

contadores .

Supongamos un programa que contenga un bucle for de la siguiente manera :

for j in rosa antonio

do

echo "Variable = $j"

done

Y la salida que produce es :

Variable es rosa

Variable es antonio

Explicación : el bloque ha efectuado dos iteraciones (dos vueltas). Para la primera ,

la variable -jtoma

el valor del primer elemento -rosa- , y para la segunda , -antonio-.

En el campo <lista> podemos sustituir la lista por patrones de ficheros para la shell

, la cual

expande dichos patrones por los ficheros correspondientes ; de tal forma que al

escribir

for j in *

la shell cambia el „*‟ por todos los ficheros del directorio actual. Por tanto , el

siguiente programa :

for j in *

do

echo $j

done

Page 18: Estructuras de Control en Shell

18

Equivale al comando „ls‟ sin opciones - merece la pena detenerse un momento para

comprender esto.

Vale también poner en el campo <lista> comillas de ejecución junto con cualquier

comando; la construcción - for j in `cat /etc/passwd` -, por ejemplo, ejecutaría

tantas iteraciones como líneas tuviese dicho fichero, y para cada vuelta, la variable -

j- contendría cada una de las líneas del mismo. Por tanto, valdrían expresiones

como - for j in `who` - para procesar todos los usuarios activos en el sistema , - for j

in `lpstat -o ` - , para procesar todos los listados pendientes , ó - for j in

`ps -e` - para tratar todos los procesos de nuestra sesión.

# programa para si los ficheros de un directorio ocupan más de 5 Mb se

truncan.

# llamar como "trunca.sh <directorio>"

case $# in

0) echo "Falta argumento"

exit 1

;;

esac

cd $1 || echo "No puedo cambiar a $1 - saliendo" ; exit 1

for j in *

do

if [ ! -f $j ]

then

continue

fi

siz=`ls -ld $j | awk „{ print $5 }‟

if [ $siz -gt 5000000 ]

then

echo "Truncando $j"

>$j

fi

done

Page 19: Estructuras de Control en Shell

19

Bucles WHILE Sintaxis :

while <condición>

do

( ... comandos ... )

Done

Aquí las iteraciones se producen mientras que la <condición> sea verdadera ( o

retorno = 0 ). En

caso que sea falsa ( o retorno != 0 ) , el bucle termina.

La sintaxis de <condición> es igual que en el comando -if- .

Ejemplo :

while [ "$opcion" != "3" ]

do

echo "Meta opcion"

read opcion

done

ó también , utilizando comandos :

echo "Escribe cosas y pulsa ^D para terminar"

while read cosa

do

echo $cosa >> /tmp/borrame

done

echo "Las lineas que has escrito son :"

cat /tmp/borrame

# programa para contar

# llamada : contar.sh <numero>

case $# in

0) echo "Falta argumento"

exit 1

;;

esac

c=0

while [ $c -le $1 ]

do

echo $c

c=`expr $c "+" 1`

done

Page 20: Estructuras de Control en Shell

20

Sintaxis De Las Sentencias De Control

El bash shell soporta un conjunto amplio de sentencias de control estructurado que

nos permiten tomar decisiones o repetir ciertos grupos de comandos con facilidad.

CASE ... IN ... ESAC La sintaxis de esta sentencia de control es la siguiente:

case e in

p1,1 | p1,2 | … | p1,n1 ) lista de comandos ;;

p1,1 | p1,2 | … | p1,n2 ) lista de comandos ;;

pm,1 | pm,2 | … | pm,n1 ) lista de comandos ;;

esac

Esta sentencia intenta encajar e en alguno de los patrones pi,j y ejecuta la lista de

comandos asociada al primer patrón en que encaje. A continuación se muestra un

ejemplo en el que se desarrolla un sencillo programa que muestra al usuario el

calendario del mes que él mismo decida. El programa acepta un parámetro en el

que el usuario indica el mes que quiere ver ya sea en formato numérico o usando

las tres primeras letras del nombre del mes en cualquier combinación de

mayúsculas o minúsculas. Si el mes seleccionado no es correcto se muestra un

mensaje de error en la pantalla.

$ cat > calendario.bsh

#!/bin/bash

mes=$1

case $mes in

[19]|

10|11|12) ;;

[Ee][Nn][Ee]) mes=1 ;;

[Ff][Ee][Bb]) mes=2 ;;

[Mm][Aa][Rr]) mes=3 ;;

[Aa][Bb][Rr]) mes=4 ;;

[Dd][Ii][Cc]) mes=12 ;;

*) echo Error

exit

;;

esac

set `date`

cal $mes $7

^D

En este programa hemos usado el comando set „date` para obtener el año actual.

Page 21: Estructuras de Control en Shell

21

IF ... THEN ... FI

Este comando permite bifurcar la ejecución de un shell script en función a un

conjunto de expresiones condicionales. Su sintaxis es la siguiente:

if l1

then

l2

elif l3

then

l4

elif l5

then

l6

else

ln

fi

El comando if ejecuta inicialmente la lista de comandos l1. Si el último comando de

esta lista tiene éxito (devuelve el código 0), entonces se ejecuta la lista de

comandos l2. Si el último comando falla se repite el mismo esquema con cada una

de las ramas elif. Si no se ejecuta con éxito la sentencia asociada a ninguna de ellas

entonces se ejecuta la lista de sentencias asociada a la rama else. Tanto las ramas

elif como la rama else son opcionales.

A continuación se muestra un sencillo ejemplo que ilustra el comando if.

$ cat > if.bsh

#!/bin/bash

echo "Teclee un número: "

read num

if (( num > 0 ))

then

echo $num es positivo

elif (( num == 0 ))

echo $num es nulo

else

echo $num es negativo

fi

^D

$ chmod ugo+x if.bsh

$ if.bsh

Teclee un número:

12

Page 22: Estructuras de Control en Shell

22

12 es positivo

$ if.bsh

Teclee un número

1

1

es negativo

En este ejemplo hemos hecho uso por primera vez del comando read que juega un

papel complementario a echo, pues sirve para leer datos desde el terminal.

FOR ... DO ... DONE Los bucles for permiten ejecutar una lista de comandos en varias ocasiones bajo el

control de una variable que toma en cada iteración un valor diferente.

A continuación mostramos la sintaxis:

for v in c1 c2 … cn

do

lista de sentencias

done

El comando for ejecuta la lista de sentencias que se le indica asignando en cada

vuelta uno de los valores c1 c2 … cn a la variable de control v. Para especificar los

valores que toma la variable de control se pueden usar patrones arbitrarios que se

sustituirán por los nombres de los ficheros que encajen en los mismos.

En el ejemplo que se muestra a continuación se desarrolla un pequeño programa

que muestra los nombre de todos los ficheros de código C que residen en el

directorio actual y en el /tmp.

$ cat > for.bsh

#!/bin/bash

for f in "Los ficheros de código C son: " *.c /tmp/*.c

do

echo $f

done

^D

$ chmod ugo+x for.bsh

Page 23: Estructuras de Control en Shell

23

WHILE ... DONE

La sintaxis de este comando es la siguiente:

while l1

do

l2

done

while ejecuta inicialmente la lista de comandos l1 y finaliza si el último comando en

ella falla. En otro caso ejecuta la lista de comandos l2 y a continuación repite el

mismo esquema una y otra vez. En el siguiente ejemplo se desarrolla un programa

que solicita al usuario un número hasta que este está entre 1 y 10.

num=0

while (( num < 1 || num > 10 ))

do

read num

done

UNTIL ... DONE La sintaxis de este comando es la siguiente:

until l1

do

l2

done

until ejecuta inicialmente la lista de comandos l1 y finaliza si el último comando en

ella tiene éxito. En otro caso ejecuta la lista de comandos l2 y a continuación repite

el mismo esquema una y otra vez.

En el siguiente ejemplo se desarrolla un programa que solicita al usuario un

número hasta que este está entre 1 y 10.

num=0

until (( num >= 1 && num <= 10 ))

do

read num

done

Page 24: Estructuras de Control en Shell

24

Estructuras Condicionales y Selectivas Ambas estructuras de programación se utilizan para escoger un bloque de código

que debe ser ejecutado tras evaluar una determinada condición. En la estructura

condicional se opta entre 2 posibilidades, mientras que en la selectiva pueden

existir un número variable de opciones

Estructuras Condicionales

La estructura condicional sirve para comprobar si se ejecuta un bloque de código

cuando se cumple una cierta condición. Pueden anidarse varias estructuras dentro

de los mismos bloques de código, pero siempre existe una única palabra fi para

cada bloque condicional.

La tabla muestra cómo se representan ambas estructuras en BASH.

Aunque el formato de codificación permite incluir toda la estructura en una línea,

cuando ésta es compleja se debe escribir en varias, para mejorar la comprensión

del programa. En caso de teclear la orden compleja en una sola línea debe tenerse

en cuenta que el carácter separador (;) debe colocarse antes de las palabras

reservadas: then, else, elif y fi.

Hay que resaltar la versatilidad para teclear el código de la estructura condicional,

ya que la palabra reservada then puede ir en la misma línea que la palabra if, en la

línea siguiente sola o conjuntamente con la primera orden del bloque de código, lo

que puede aplicarse también a la palabra else).

Puede utilizarse cualquier expresión condicional para evaluar la situación,

incluyendo el código de salida de un mandato o una condición evaluada por la

orden interna test. Este último caso se expresa colocando la condición entre

corchetes (formato: [ Condición ]).

Page 25: Estructuras de Control en Shell

25

Véanse algunos sencillos ejemplos de la estructura condicional simple extraídos del

“script” /etc/rc.d/rc.sysinit. Nótese la diferencia en las condiciones sobre la salida

normal de una orden –expresada mediante una sustitución de mandatos– y

aquellas referidas al estado de ejecución de un comando (si la orden se ha

ejecutado correctamente o si se ha producido un error).

# La condición más simple escrita en una línea:

# si RESULT>0; entonces rc=1

if [ $RESULT -gt 0 ]; then rc=1; fi

#

# La condición doble:

# si la variable HOSTNAME es nula o vale “(none)”; entonces ...

if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then

HOSTNAME=localhost

fi

#

# Combinación de los 2 tipos de condiciones:

# si existe el fichero /fastboot o la cadena “fastboot” está

# en el fichero /proc/cmdline; entonces ...

if [ -f /fastboot ] || grep -iq "fastboot" /proc/cmdline \

2>/dev/null; then

fastboot=yes

fi

Obsérvense los ejemplos para las estructuras condicionales complejas, basados

también en el programa de configuración /etc/rc.d/rc.sysinit.

# Estructura condicional compleja con 2 bloques:

# si existe el fichero especificado, se ejecuta; si no, se da

# el valor “no” a la variable NETWORKING

if [ -f /etc/sysconfig/network ];

then

. /etc/sysconfig/network

else

NETWORKING=no

fi

# Estructura anidada:

# si rc=0; entonces ...; si no, si rc=1; entonces ...; en caso

# contrario; no se hace nada.

if [ "$rc" = "0" ]; then

success "$STRING"

Page 26: Estructuras de Control en Shell

26

echo

elif [ "$rc" = "1" ]; then

passed "$STRING"

echo

fi

Por último, evaluar el siguiente ejercicio:

if [ -f /etc/sysconfig/console/default.kmap ]; then

KEYMAP=/etc/sysconfig/console/default.kmap

else

if [ -f /etc/sysconfig/keyboard ]; then

. /etc/sysconfig/keyboard

fi

if [ -n "$KEYTABLE" -a -d "/usr/lib/kbd/keymaps" -o -d

"/lib/kbd/keymaps" ]; then

KEYMAP=$KEYTABLE

fi

fi

Estructura Selectiva

La estructura selectiva evalúa la condición de control y, dependiendo del resultado,

ejecuta un bloque de código determinado. La siguiente tabla muestra el formato

genérico de esta estructura.

Las posibles opciones soportadas por la estructura selectiva múltiple se expresan

mediante patrones, donde puede aparecer caracteres comodines, evaluándose

como una expansión de ficheros, por lo tanto el patrón para representar la opción

por defecto es el asterisco (*).

Dentro de una misma opción pueden aparecer varios patrones separados por la

barra vertical (|), como en una expresión lógica O.

Si la expresión que se comprueba cumple varios patrones de la lista, sólo se ejecuta

el bloque de código correspondiente al primero de ellos, ya que la evaluación de la

estructura se realiza en secuencia.

Page 27: Estructuras de Control en Shell

27

Obsérvense los siguientes ejemplos:

# Según el valor de la variable UTC:

# - si es “yes” o “true”, ...

# - si es “no” o “false”, ...

case "$UTC" in

yes|true) CLOCKFLAGS="$CLOCKFLAGS --utc";

CLOCKDEF="$CLOCKDEF (utc)";

;;

no|false) CLOCKFLAGS="$CLOCKFLAGS --localtime";

CLOCKDEF="$CLOCKDEF (localtime)";

;;

Esac

Y, como en los casos anteriores, describir el modo de ejecución de la siguiente

estructura selectiva:

case "$SO" in

AIX) echo –n "$US: "

lsuser -ca expires $US|fgrep -v "#"|cut -f2 -d:`"

;;

SunOS) echo "$US: `logins -aol $US|cut -f7 -d:`"

;;

Linux) echo "$US: `chage -l $US|grep Account|cut -f2 -d:`"

;;

*) echo "Sistema operativo desconocido" ;;

esac

Page 28: Estructuras de Control en Shell

28

Bucles Los bucles son estructuras reiterativas que se ejecutan repetitivamente, para no

tener que teclear varias veces un mismo bloque de código. Un bucle debe tener

siempre una condición de salida para evitar errores provocados por bucles infinitos.

La siguiente tabla describe las 2 órdenes especiales que pueden utilizarse para

romper el modo de operación típico de un bucle.

Los siguientes puntos describen los distintos bucles que pueden usarse tanto en un

guión como en la línea de mandatos de BASH.

Bucles Genéricos Los bucles genéricos de tipos “para cada” ejecutan el bloque de código para cada

valor asignado a la variable usada como índice del bucle o a su expresión de

control. Cada iteración debe realizar una serie de operaciones donde dicho índice

varíe, hasta la llegar a la condición de salida.

El tipo de bucle for más utilizado es aquél que realiza una iteración por cada

palabra (o cadena) de una lista. Si se omite dicha lista de valores, se realiza una

iteración por cada parámetro posicional.

Por otra parte, BASH soporta otro tipo de bucle iterativo genérico similar al usado

en el lenguaje de programación C, usando expresiones aritméticas. El modo de

operación es el siguiente:

· Se evalúa la primera expresión aritmética antes de ejecutar el bucle para dar un

valor inicial al índice.

· Se realiza una comprobación de la segunda expresión aritmética, si ésta es falsa se

ejecutan las iteraciones del bucle. Siempre debe existir una condición de salida

para evitar que el bucle sea infinito.

· como última instrucción del bloque se ejecuta la tercera expresión aritmética –que

debe modificar el valor del índice– y se vuelve al paso anterior.

Page 29: Estructuras de Control en Shell

29

La siguiente tabla describe los formatos de los bucles iterativos genéricos (de tipo

“para cada”) interpretados por BASH.

Véanse algunos ejemplos:

# Se asigna a la variable “library” el camino de cada uno de

# los archivos indicados en la expansión de ficheros y se

# realizan las operaciones indicadas en el bloque de código.

for library in /lib/kernel/$(uname -r)/libredhat-kernel.so* ; do

ln -s -f $library /lib/

ldconfig -n /lib/

done

...

# Se establece un contador de hasta 20 iteraciones para

# ejecutar el bucle.

for (( times = 1; times < 20; times++ )); do

/usr/sbin/rpcinfo -p | grep ypbind > /dev/null 2>&1 && \

ypwhich > /dev/null 2>&1

done

Y el ejercicio a evaluar:

for US in `cut -sf2 -d: /home/cdc/*.lista`; do

grep "^$US:" /etc/shadow | cut -sf1-2 -d: >>$FICHTEMP

done

Page 30: Estructuras de Control en Shell

30

Bucles Condicionales While & Until

Los bucles condicionales evalúan la expresión en cada iteración del bucle y

dependiendo del resultado se vuelve a realizar otra iteración o se sale a la

instrucción siguiente.

La siguiente tabla describe los formatos para los 2 tipos de bucles condicionales

soportados por el intérprete BASH.

Ambos bucles realizan comparaciones inversas y pueden usarse indistintamente,

aunque se recomienda usar aquél que necesite una condición más sencilla o

legible, intentando no crear expresiones negativas. Véase el siguiente ejemplo:

# Mientras haya parámetros que procesar, ...

while [ $# != 0 ] ; do

processdir "$1"

shift

done

Se proponen como ejercicios convertir este bucle while en un bucle until y en uno

for de estilo C.

i=5

while [ $i -ge 0 ] ; do

if [ -f /var/log/ksyms.$i ] ; then

mv /var/log/ksyms.$i /var/log/ksyms.$(($i+1))

fi

i=$(($i-1))

2done

Page 31: Estructuras de Control en Shell

31

Bucle de Selección Interactiva

La estructura select no es propiamente dicho un bucle de programación

estructurada, ya que se utiliza para mostrar un menú de selección de opciones y

ejecutar el bloque de código correspondiente a la selección escogida. En caso de

omitir la lista de palabras, el sistema

presenta los parámetros posicionales del programa o función. Este tipo de bucles

no suele utilizarse.

La siguiente tabla describe el formato del bucle interactivo.

Page 32: Estructuras de Control en Shell

32

CONCLUSIONES

El programar en shell es muy similar a un oficio común, por ejemplo: un carpintero.

Un carpintero tiene una caja de herramientas que contiene todas las cosas que

utiliza para su oficio, en esa caja puede haber desarmadores, tornillos, taladros, etc.

El carpintero utiliza estas herramientas de diferente manera y en diferentes

combinaciones para lograr resultados diferentes, no se utiliza la misma herramienta

para hacer un juguete que para hacer un escritorio y es posible que si se utilice la

misma no se utilice en la misma intensidad o forma.

Aplicando estas mismas herramientas, el carpintero es capaz de construir los

diferentes elementos necesarios para construir sus proyectos.

Para construir algún objeto de madera, se necesitan las herramientas correctas. En

Unix, las herramientas que se utilizan son llamadas "utilerías" o "comandos". Existen

comandos simples como ls y cd, y existen herramientas más complejas como awk,

sed, y el mismo shell. Uno de los problemas más comunes de trabajar con madera,

es la de utilizar la herramienta o técnica incorrecta para construir algún proyecto. El

saber que herramienta utilizar, normalmente se obtiene con la experiencia.

Las herramientas más poderosas, normalmente toman más tiempo para entender y

aprovechar.

Page 33: Estructuras de Control en Shell

33

BIBLIOGRAFÍA

1. B. Fox, C. Ramey: “BASH(1)” (páginas de manuales de BASH v2.5a)”. 2.001.

2. C. Ramey, B. Fox: “Bash Reference Manual, v2.5a”. Free Software Foundation, 2.001.

3. Mike G, trad. G. Rodríguez Alborich: “Programación en BASH – COMO de

Introducción”. 2.000.

4. M. Cooper: “Advanced Bash-Scripting Guide, v2.1”. Linux Documentation Project,

2.003.

5. R. M. Gómez Labrador: “Administración de Sistemas Linux Red Hat”. Secretariado de

Formación Permanente del PAS (Universidad de Sevilla), 2.002.

MESOGRAFÍA

i. Proyecto GNU.: http://www.gnu.org/

ii. The Linux Documentation Project (TLDP): http://www.tldp.org/

iii. Proyecto HispaLinux (LDP-ES): http://www.hispalinux.es/