Está en la página 1de 42

Universidad de Murcia

Facultad de Informtica Departamento de Ingeniera y Tecnologa de Computadores


rea de Arquitectura y Tecnologa de Computadores

PRCTICAS DE I.S.O.
T TULO DE G RADO EN I NGENIERA I NFORMTICA
Boletines de Prcticas 1-4 Programacin de shell scripts en Linux M ARZO DE

ndice
1. CONCEPTO DE SHELL EN LINUX 2. FUNCIONAMIENTO DEL SHELL 3. VARIABLES Y PARMETROS 3.1. Variables . . . . . . . . . . . . . 3.2. Parmetros . . . . . . . . . . . . 3.3. Reglas de evaluacin de variables 3.4. Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 5 5 5 7 8 9 10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 11 12 13 13 14 14 17 18 20 21 23 25 25 25 26 26 27 27 27 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 28 28 29 29 29 30 32

4. CARACTERES ESPECIALES Y DE ENTRECOMILLADO 5. ESTRUCTURAS DE CONTROL 5.1. Condiciones: if y case . . . . . . . . . 5.2. Bucles condicionales: while y until . 5.3. Bucles incondicionales: for y seq . . . 5.4. Mens de opciones: select . . . . . . . . 5.5. Ruptura de bucles: break y continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6. EJEMPLOS DE GUIONES SHELL. PRIMERA SESION 7. EJERCICIOS PROPUESTOS. PRIMERA SESION 8. ENTRADA/SALIDA ESTNDAR Y REDIRECCIN 9. RDENES INTERNAS DE BASH 10. EVALUACIN ARITMTICA 11. LA ORDEN test 12. RDENES SIMPLES, LISTAS DE RDENES Y RDENES COMPUESTAS 12.1. rdenes simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2. Listas de rdenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.3. rdenes compuestas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13. FUNCIONES 13.1. Ejemplo de funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.2. Ejemplo de funciones con parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14. DEPURACIN 15. PATRONES DE USO DEL SHELL 15.1. Comprobacin de cadena vaca . . . . . . . . . . . . . . . . . . . . . . 15.2. Uso de xargs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.3. Leer un chero lnea a lnea . . . . . . . . . . . . . . . . . . . . . . . . 15.4. Comprobar si una determinada variable posee un valor numrico vlido 15.5. Leer argumentos opcionales de la lnea de comandos . . . . . . . . . . 16. EJEMPLOS DE GUIONES SHELL. SEGUNDA SESION 17. EJERCICIOS PROPUESTOS. SEGUNDA SESION

18. TERCERA SESION: EJERCICIOS DE EXAMENES (1/2) 19. CUARTA SESION: EJERCICIOS DE EXAMENES (2/2) 20. BIBLIOGRAFA

35 39 42

1. CONCEPTO DE SHELL EN LINUX


Un shell es un intrprete de rdenes, y un intrprete de rdenes es un programa que procesa todo lo que se escribe en el terminal. Bsicamente, permite a los usuarios interactuar con el sistema operativo para darle rdenes. En otras palabras, el objetivo de cualquier intrprete de rdenes es procesar los comandos o ejecutar los programas que el usuario teclea. El prompt es una indicacin que muestra el intrprete para anunciar que espera una orden del usuario. Cuando el usuario escribe una orden, el intrprete la ejecuta. Dicha orden puede ser interna o externa. Las rdenes internas son aquellas que vienen incorporados en el propio intrprete, como, por ejemplo, echo, cd, o pwd. Las externas, por el contrario, son programas separados como, por ejemplo, todos los programas que residen en los directorios /bin (como ls), /usr/bin (como cut), /sbin (como fsck) o /usr/sbin (como lpc). En el mundo UNIX/Linux existen tres grandes familias de shells: sh, csh y ksh. Se diferencian entre s, fundamentalmente, en la sintaxis de sus rdenes y en su interaccin con el usuario. En estas prcticas nos centraremos en el uso del shell bash, una variante libre de la familia sh. Por defecto, cada usuario tiene asignado un shell, establecido en el momento de creacin de su cuenta, y que se guarda en el chero /etc/passwd. En los laboratorios de prcticas se puede consultar ese chero con la orden ypcat passwd. El shell asignado a un usuario se puede cambiar de dos maneras: editando manualmente dicho chero (lo cual slo puede hacer el administrador del sistema), o bien con el programa chsh (que lo puede ejecutar el propio usuario). Los shells estn en los directorios /bin y /usr/bin1 . Por ejemplo, para hacer que el shell por defecto sea /bin/bash se ejecutara: chsh -s /bin/bash Una de las principales caractersticas del shell es que puede programarse usando cheros de texto a partir de rdenes internas y programas externos. Adems, el shell ofrece construcciones y facilidades para hacer ms sencilla su programacin. Estos cheros de texto se llaman scripts, shell scripts o guiones shell. Tras su creacin, estos guiones shell pueden ser ejecutados tantas veces como se desee. Una posible denicin podra ser la siguiente: Un guin de shell es un chero de texto ejecutable que contiene una secuencia de rdenes ejecutables por el shell. Un guin shell puede incluir comentarios. Para ello se utiliza el carcter # al inicio del texto que constituye el comentario. Adems, en un guin shell se puede indicar el shell concreto con el que se debe interpretar o ejecutar, indicndolo en la primera lnea de la siguiente forma (el carcter # no es un comentario en este caso): #!/bin/bash La programacin de guiones shell es una de las herramientas ms apreciadas por todos los administradores y muchos usuarios de UNIX/Linux ya que permite automatizar tareas complejas y/o repetitivas, y ejecutarlas con una sola llamada al script, incluso de manera automtica a una hora preestablecida sin intervencin humana. A continuacin se muestran una serie de ejemplos de distintas tareas que se suelen automatizar con scripts: Tareas administrativas denidas por el propio sistema o por su administrador . Por un lado, algunas partes de los sistemas UNIX/Linux son guiones shell. Para poder entenderlos y modicarlos es necesario tener alguna nocin sobre la programacin de scripts. Por otro lado, el administrador del sistema puede necesitar llevar a cabo tareas de mantenimiento del sistema de manera regular. El uso de guiones shell permite automatizarlas fcilmente en la mayor parte de los casos. Tareas tediosas, incluso aquellas que slo se van a ejecutar una o dos veces, para las que no importa el rendimiento obtenido durante su realizacin pero s que se terminen con rapidez. Integracin de varios programas independientes para que funcionen como un conjunto de forma sencilla. Desarrollo de prototipos de aplicaciones ms complejas que posteriormente se implementarn en lenguajes ms potentes.
1 El

chero /etc/shells contiene una lista de los shells disponibles.

Conocer a fondo el shell aumenta tremendamente la rapidez y productividad a la hora de utilizarlo, incluso sin hacer uso de guiones (es decir, utilizndolo simplemente desde el prompt del sistema). Los guiones shell pueden utilizar un sin nmero de herramientas como: rdenes del sistema internas o externas, por ejemplo, rdenes como echo, ls, etc. Lenguaje de programacin del shell, por ejemplo, construcciones como if/then/else/fi, etc. Programas y/o lenguajes de procesamiento en lnea como sed o awk. Programas propios del usuario escritos en cualquier lenguaje de programacin. Si un guin shell no resulta suciente para lo que queremos hacer, existen otros lenguajes interpretados mucho ms potentes como Perl, TCL o Python. El intrprete de rdenes seleccionado para realizar estas prcticas es el Bourne-Again Shell o bash, cuyo ejecutable es /bin/bash. El resto del contenido de este documento est centrado en este intrprete de rdenes.

2. FUNCIONAMIENTO DEL SHELL


Suponiendo que tenemos el siguiente guin shell, #!/bin/bash clear date al ejecutarse el proceso que se sigue es el siguiente: 1. El shell /bin/bash hace un fork. 2. El proceso padre espera mientras no termina el nuevo proceso hijo. 3. El proceso hijo hace un fork y un exec para ejecutar la orden clear, y a continuacin ejecuta un wait para esperar a que termine la ejecucin de clear. 4. Una vez que ha terminado la orden clear, el proceso hijo repite los mismos pasos pero esta vez ejecutando la orden date. 5. Si quedasen rdenes por ejecutar se seguira el mismo procedimiento. 6. Cuando naliza el proceso hijo, el proceso padre reanuda su ejecucin.

3. VARIABLES Y PARMETROS
3.1. Variables
Cada shell tiene unas variables ligadas a l, a las que el usuario puede aadir tantas como desee. Para dar un valor a una variable variable se usa la sintaxis: variable=valor Ntese que no puede haber espacios entre el nombre de la variable, el signo = y el valor. Por otra parte, si se desea que el valor contenga espacios, es necesario utilizar comillas. Para obtener el valor de una variable hay que anteponerle a su nombre el carcter $. Por ejemplo, para visualizar el valor de una variable: echo $variable

Un ejemplo del uso de las variables sera: $ mils="ls -l" # $ mils # # $ $mils # $ echo $mils # # Se crea una nueva variable No hace nada porque busca el ejecutable mils que no existe Ejecuta la orden "ls -l" Muestra el contenido de la variable mils, es decir, "ls -l"

Las variables se dividen en dos tipos: Variables locales: no son heredadas por los procesos hijos del shell actual cuando se realiza un fork. Variables de entorno: heredadas por los procesos hijos del shell actual cuando se ejecuta un fork. La orden export convierte una variable local en variable de entorno: $ export mils # Convierte la variable mils en variable de entorno $ export var=valor # Crea la variable, le asigna "valor" # y la exporta a la vez La orden set muestra todas las variables (locales y de entorno) mientras que la orden env muestra slo las variables de entorno. Con la orden unset se pueden restaurar o eliminar variables o funciones. Por ejemplo, la siguiente instruccin elimina el valor de la variable mils: $ unset mils Adems de las variables que puede denir el programador, un shell tiene denidas, por defecto, una serie de variables. Las ms importantes son: PS1: prompt primario. El siguiente ejemplo modica el prompt, utilizando diferentes para el nombre del usuario y el host, y el directorio actual: $ PS1=\[\033[31m\]\u@\h\[\033[0m\]:\[\033[33m\]\w\[\033[0m\] $ PS2: prompt secundario. LOGNAME: nombre del usuario. HOME: directorio de trabajo (home) del usuario actual que la orden cd toma por defecto. PWD: directorio actual. PATH: rutas de bsqueda usadas para ejecutar rdenes o programas. Por defecto, el directorio actual no est incluido en la ruta de bsqueda. Para incluirlo, tendramos que ejecutar P AT H =PATH:.: TERM: tipo de terminal actual. SHELL: shell actual. Las siguientes variables son muy tiles al programar los guiones shell: $?: esta variable contiene el valor devuelto por la ltima orden ejecutada que es til para saber si una orden ha nalizado con xito o ha tenido problemas. Un 0 indica que la orden se ha ejecutado con xito, otro valor indica que ha habido errores. $!: identicador de proceso (PID) de la ltima orden ejecutada en segundo plano. $$: el PID del shell actual (comnmente utilizado para crear nombres de cheros nicos).

$-: las opciones actuales suministradas para esta invocacin del shell. $*: todos los argumentos del guin shell comenzando por el $1. Cuando la expansin ocurre dentro comillas dobles, se expande a una sola palabra con el valor de cada parmetro separado por el primer carcter de la variable especial IFS (habitualmente un espacio). En general, $* es equivalente a $1c$2c..., donde c es el primer carcter del valor de la variable IFS. Si IFS no est denida, el carcter c se sustituye por un espacio. Si IFS es la cadena vaca, los parmetros se concatenan sin ningn separador. $@: igual que la anterior excepto cuando va entrecomillada. Cuando la expansin ocurre dentro de comillas dobles, cada parmetro se expande a una palabra separada, esto es, $@ es equivalente a $1 $2. . .

3.2. Parmetros
Como cualquier programa, un guin shell puede recibir parmetros en la lnea de rdenes para procesarlos durante su ejecucin. Los parmetros recibidos se guardan en una serie de variables que el script puede consultar cuando lo necesite. Los nombres de estas variables son: $1 $2 $3 ... ${10} ${11} ${12} ... La variable $0 contiene el nombre con el que se ha invocado el script, $1 contiene el primer parmetro, $2 contiene el segundo parmetro,. . . A continuacin se muestra un sencillo ejemplo de un guin shell que muestra los cuatro primeros parmetros recibidos: #!/bin/bash echo El nombre del programa es $0 echo El primer parmetro recibido es $1 echo El segundo parmetro recibido es $2 echo El tercer parmetro recibido es $3 echo El cuarto parmetro recibido es $4 La orden shift mueve todos los parmetros una posicin a la izquierda, esto hace que el contenido del parmetro $1 desaparezca, y sea reemplazado por el contenido de $2, que $2 sea reemplazado por $3, etc. La variable $# contiene el nmero de parmetros que ha recibido el script. Como se indic anteriormente $* o $@ contienen todos los parmetros recibidos. La variable $@ es til cuando queremos pasar a otros programas algunos de los parmetros que nos han pasado. Un ejemplo sencillo de un guin shell que muestra el nombre del ejecutable, el nmero total de parmetros, todos los parmetros y los cuatro primeros parmetros es el siguiente: #!/bin/bash echo El nombre del programa es $0 echo El nmero total de parmetros es $# echo Todos los parmetros recibidos son $* echo El primer parmetro recibido es $1 shift echo El segundo parmetro recibido es $1 shift echo El tercer parmetro recibido es $1 echo El cuarto parmetro recibido es $2

3.3. Reglas de evaluacin de variables


A continuacin se describen las reglas que gobiernan la evaluacin de las variables de un guin shell: $var: valor de var si est denida, si no nada. ${var}: igual que el anterior excepto que las llaves contienen el nombre de la variable a ser evaluada. ${var-thing}: valor de var si est denida, si no thing. ${var=thing}: igual que el anterior excepto cuando var no est denida en cuyo caso el valor de var pasa a ser thing. ${var?message}: valor de var si est denida, si no imprime el mensaje en el terminal. ${var+thing}: thing si var est denida, si no nada. El siguiente ejemplo muestra cmo podemos usar una variable asignndole un valor en caso de que no est denida: $ echo El valor de var1 es ${var1} # No est definida, no imprimir nada $ echo El valor de la variable es ${var1=5} # Al no estar definida, le asigna el valor 5 $ echo Su nuevo valor es $var1 # Su valor es 5 Pero si lo que queremos es usar un valor por defecto, en caso de que la variable no est denida, sin inicializar la variable: $ echo El valor de var1 es ${var1} # No est definida, no imprimir nada $ echo El valor de la variable es ${var1-5} # Al no estar definida, utiliza el valor 5 $ echo El valor es $var1 # Su valor sigue siendo nulo, no se ha definido Por otro lado, si lo que queremos es usar el valor de la variable y, en caso de que no est denida, imprimir un mensaje: $ echo El valor de var1 es ${var1} # No est definida, no imprimir nada $ echo El valor de la variable es ${var1? No est definida...} # Al no estar definida, se muestra en pantalla el mensaje $ echo El valor es $var1 # Su valor sigue siendo nulo, no se ha definido

Este ltimo ejemplo nos muestra cmo utilizar un valor por defecto si una variable est denida: $ var1=4 # Le asigna el valor 4

$ echo El valor de var1 es ${var1} # El valor mostrado ser 4 $ echo El valor de la variable es ${var1+5} # Al estar definida, se utiliza el valor 5 $ echo El valor es $var1 # Su valor sigue siendo 4

3.4. Arrays
El shell permite que se trabaje con arrays (o listas) unidimensionales. Un array es una coleccin de elementos del mismo tipo, dotados de un nombre, y que se almacenan en posiciones contiguas de memoria. El primer subndice del primer element del array es 0, y si no se utiliza subndice, se considera tambin que se est referenciando a dicho elemento. No hay un tamao mximo para un array, y la asignacin de valores se puede hacer de forma alterna. La sintaxis para crear e inicializar un array es la siguiente: nombre_array=(val1 val2 val3 ...) # Crea e inicializa un array nombre_array[x]=valor # Asigna un valor al elemento x Para acceder a un elemento del array se utiliza la siguiente sintaxis: ${nombre_array[x]} # Para acceder al elemento x ${nombre_array[*]} # Para consultar todos los elementos ${nombre_array[@]} # Para consultar todos los elementos La diferencia entre usar * y @ es que ${nombre_array[*]} crea una nica palabra con todos los elementos del array mientras que ${nombre_array[@]} crea palabra distintas para cada elemento del array. Para conocer el tamao en bytes de un elemento dado del array se utiliza la sintaxis ${#nombre_array[x]}, donde x es un ndice del array. De hecho, esa misma expresin vale tambin para saber la longitud de una simple variable normal (por ejemplo, ${#var}). Si lo que nos interesa, por el contrario, es saber el nmero total de elementos del array, entonces emplearemos las expresiones ${#nombre_array[*]} o ${#nombre_array[@]}. Ntese la diferencia entre las siguientes rdenes: $ aux=ls $ aux1=(ls) En el primer caso, la variable aux contiene la salida de ls como una cadena de caracteres. En el segundo caso, al haber utilizado los parntesis, aux1 es un array, y cada uno de sus elementos es uno de los nombres de chero devueltos por la orden ls. Si en el directorio actual tenemos los cheros a.latex, b.latex, c.latex, d.latex, e.latex y f.latex, observe el resultado de ejecutar las rdenes anteriores: $ ls a.latex b.latex c.latex d.latex e.latex f.latex $ aux=ls $ echo $aux a.latex b.latex c.latex d.latex e.latex f.latex $ echo ${aux[0]} a.latex b.latex c.latex d.latex e.latex f.latex $ aux1=(ls) $ echo ${aux1[0]} a.latex

4. CARACTERES ESPECIALES Y DE ENTRECOMILLADO


Los mecanismos de proteccin se emplean para quitar el signicado especial para el shell de ciertos caracteres especiales o palabras reservadas. Pueden emplearse para que caracteres especiales no se traten de forma especial, para que palabras reservadas no sean reconocidas como tales, y para evitar la evaluacin de variables. Los metacaracteres (* $ | & ; ( ) < > espacio tab) tienen un signicado especial para el shell y deben ser protegidos o entrecomillados si quieren representarse a s mismos. Hay 3 mecanismos de proteccin: el carcter de escape, las comillas simples y las comillas dobles2 . Una barra inclinada inversa (o invertida) no entrecomillada (\) es el carcter de escape, (no confundir con el cdigo ASCII cuyo valor es 27 en decimal), el cual preserva el valor literal del siguiente carcter que lo acompaa, con la excepcin de <nueva-lnea>. Si aparece la combinacin \<nueva-lnea> y la barra invertida no est entre comillas, la combinacin \<nueva-lnea> se trata como una continuacin de lnea (esto es, se quita del ujo de entrada y no se tiene en cuenta). Por ejemplo, sera equivalente a ejecutar ls -l: $ ls \ > -l Encerrar caracteres entre comillas simples ( ) preserva el valor literal de cada uno de ellos entre las comillas. Una comilla simple no puede estar entre comillas simples, ni siquiera precedida de una barra invertida. $ echo caracteres especiales: *, $, |, &, ;, (,),{,},<,>, \, ", caracteres especiales: *, $, |, &, ;, (,),{,},<,>, \, ", Encerrar caracteres entre comillas dobles ( ) preserva el valor literal de todos los caracteres, con la excepcin de $, , y \. Los caracteres $ y mantienen su signicado especial dentro de comillas dobles. La barra invertida mantiene su signicado especial solamente cuando est seguida por uno de los siguientes caracteres: $, , ", o <nueva-lnea>. Una comilla doble puede aparecer entre otras comillas dobles precedida de una barra invertida. $ echo "caracteres especiales: *, \$, |, &, ;, (,),{,},<,>, \\, \", \" caracteres especiales: *, $, |, &, ;, (,),{,},<,>, \, ", Los parmetros especiales $* y $@ tienen un signicado especial cuando estn entre comillas dobles (vanse los apartados 3.1 y 3.2). Las expresiones de la forma $cadena se tratan de forma especial. Las secuencias de escape con barra invertida de cadena, si estn presentes, son reemplazadas segn especica el estndar ANSI/ISO de C, y el resultado queda entre comillas simples: \a: alerta (campana) \b: espacio-atrs \e: carcter de escape (ESC) \f: nueva pgina \n: nueva lnea \r: retorno de carro \t: tabulacin horizontal \v: tabulacin vertical \\: barra invertida \xnnn: carcter cuyo cdigo es el valor hexadecimal nnn
2 Las

comillas simples y dobles son las que aparecen en la tecla que hay a la derecha de la ee y en la tecla del 2, respectivamente.

10

Encerrar una cadena entre comillas invertidas ( ), o bien entre parntesis precedida de un signo $, supone forzar al shell a ejecutarla como una orden y devolver su salida: orden $(orden) Este proceso se conoce como sustitucin de rdenes. A continuacin se muestran varios ejemplos: $ $ $ $ aux=ls -lai echo $aux fecha=$(date) echo $fecha # # # # Ejecuta Muestra Ejecuta Muestra ls -lai y almacena el resultado en aux el contenido de aux date y almacena el resultado en fecha el contenido de fecha

Tngase en cuenta que el shell, antes de ejecutar una orden, procesa todos los caracteres especiales (en funcin de los mecanismos de proteccin), expande las expresiones regulares3 , y realiza la sustitucin de rdenes: $ $ $ $ $ $ echo * var=ls echo $var echo $var echo "$var" echo date # # # # # # Muestra Primero Muestra Imprime Muestra Primero todos los ficheros del directorio actual ejecuta ls -la y luego almacena el resultado en var el contenido de var, esto es, equivale a echo * $var el contenido de var, esto es, equivale a echo * se ejecuta date y luego echo

5. ESTRUCTURAS DE CONTROL
5.1. Condiciones: if y case
En un guin shell se pueden introducir condiciones, de forma que determinadas rdenes slo se ejecuten cuando stas se cumplen. Para ello se utilizan las rdenes if y case, con la siguiente sintaxis: if [ expresin ] # Habitualmente un test then rdenes a ejecutar si se cumple la primera condicin elif [ expresin ] then rdenes a ejecutar si se cumple la segunda condicin # (el bloque elif y sus rdenes son opcionales) ... else rdenes a ejecutar en caso contrario # (el bloque else y sus rdenes son opcionales) fi La expresin a evaluar por if puede ser un test, una lista de rdenes (usando su valor de retorno), una variable o una expresin aritmtica, esto es, bsicamente cualquier orden que devuelva un cdigo en $?. Un ejemplo del funcionamiento de la orden if sera: if grep -q main prac.c then echo encontrada la palabra clave main else echo no encontrada la palabra clave main fi
3 La

generacin de nombres de cheros se basa habitualmente en expresiones regulares tal y como se describe en la utilizacin de los comandos find y grep que se realiza en el documento Ejemplos de uso de distintas rdenes, proporcionado con la primera prctica.

11

La sintaxis de la orden case es la siguiente: case $var in v1) .. .. ;; v2|v3) .. .. ;; .. *) ;; esac

# Caso por defecto

v1, v2 y v3 son expresiones regulares similares a las utilizadas como comodines para los nombres de los cheros. Un ejemplo de su funcionamiento podra ser: case $var 1) ;; 2) ;; *) ;; esac in echo La variable var es un uno echo La variable var es un dos echo La variable var no es ni un uno ni un dos

5.2. Bucles condicionales: while y until


Tambin es posible ejecutar bloques de rdenes de forma iterativa dependiendo de una condicin. La comprobacin puede realizarse al principio (while) o al nal (until). La sintaxis es la siguiente: while do ... done until do ... done [ expresin ] # Mientras la expresin sea cierta...

[ expresin ]

# Mientras la expresin sea falsa...

Un ejemplo del funcionamiento de ambas rdenes sera: # Muestra todos los parmetros while [ ! -z $1 ] do echo Parmetro: $1 shift done # Tambin muestra todos los parmetros until [ -z $1 ] do echo $1 shift done

12

5.3. Bucles incondicionales: for y seq


Con la orden for se ejecutan bloques de rdenes, permitiendo que en cada iteracin una determinada variable tome un valor distinto. La sintaxis es la siguiente: for var in lista do uso de $var done Por ejemplo: for i in 10 30 70 do echo Mi nmero favorito es $i # toma los valores 10, 30 done

y 70

Aunque la lista de valores del for puede ser arbitraria (incluyendo no slo nmeros, sino cualquier otro tipo de cadena o expresin), a menudo lo que queremos es generar secuencias de valores numricos al estilo de la instruccin for de los lenguajes de programacin convencionales. En este caso, el comando seq, combinado con el mecanismo de sustitucin de rdenes (vase el apartado 4) puede resultarnos de utilidad. Por ejemplo: for i in seq 0 5 25 do # uso de $i que toma los valores 0, 5, 10, 15, 20 y 25 done

5.4. Mens de opciones: select


Con la orden select podemos solicitar al usuario que elija una opcin de una lista. La sintaxis de la orden select es: select opcion in [ lista ] ; do # bloque de rdenes done select genera una lista numerada de opciones al expandir la lista lista. A continuacin, presenta un prompt (#?) al usuario pidindole que elija una de las posibilidades, y lee de la entrada estndar la opcin elegida. Si la respuesta dada es uno de los nmeros de la lista presentada, dicho nmero se almacena en la variable REPLY, la variable opcion toma el valor del elemento de la lista elegido, y se ejecuta el bloque de rdenes. Si la respuesta es no vlida, se vuelve a interrogar al usuario, y si es EOF, se naliza. El bloque de rdenes se ejecuta despus de cada seleccin vlida, mientras no se termine, bien con break o bien con EOF. El valor de salida de select ser igual al valor de la ltima orden ejecutada. Un ejemplo sera el siguiente: select respuesta in "Ver contenido directorio actual" \ "Salir" do echo Ha seleccionado la opcin: $respuesta case $REPLY in 1) ls . ;; 2) break ;; esac done

13

En pantalla aparecera: 1) Ver contenido directorio actual 2) Salir #? Si se selecciona la primera opcin, 1, se mostrara el mensaje: Ha seleccionado la opcin: Ver contenido directorio actual, se ejecutara la orden ls en el directorio actual, y volvera a pedir la siguiente seleccin. Si por el contrario se pulsase un 2, seleccionando la segunda opcin, aparecera el mensaje: Ha seleccionado la opcin: Salir, y se saldra del select.

5.5. Ruptura de bucles: break y continue


Las rdenes break y continue sirven para interrumpir la ejecucin secuencial del cuerpo de un bucle. La orden break transere el control a la orden que sigue a done, haciendo que el bucle termine antes de tiempo. La orden continue, por el contrario, transere el control a done, haciendo que se evale de nuevo la condicin, es decir, la ejecucin del bucle contina en la siguiente iteracin. En ambos casos, las rdenes del cuerpo del bucle siguientes a estas sentencias no se ejecutan. Lo normal es que formen parte de una sentencia condicional. Un par de ejemplos de su uso seran: # Muestra todos los parmetros, si encuentra una "f" finaliza while [ $# -gt 0 ] do if [ $1 = "f" ] then break fi echo Parmetro: $1 shift done # Muestra todos los parmetros, si encuentra una "f" # se lo salta y contina el bucle while [ $# -gt 0 ] do if [ $1 = "f" ] then shift continue fi echo Parmetro: $1 shift done

6. EJEMPLOS DE GUIONES SHELL. PRIMERA SESION


1. El siguiente programa llamar, muestra su nmero PID y despus llama a un programa llamado num, a travs de la orden (.). Cuando num termina su ejecucin, la orden (.) devuelve el control al programa que lo llam, el cual muestra el mensaje. Guin llamar echo "$0 PID = $$" . num echo "se ejecuta esta lnea"

14

Guin num echo "num PID = $$" Como vemos, la orden (.) ejecuta un proceso como parte del proceso que se est ejecutando (llamar y num tienen el mismo nmero de proceso). Cuando el nuevo programa termina la ejecucin, el proceso actual contina ejecutando el programa original. El programa num no necesita permiso de ejecucin. 2. Programa que evala la extensin de un chero. Si sta se corresponde con txt, copia el chero al directorio ~/copias. Si es otra la extensin o no hace nada o presenta un mensaje. case $1 in *.txt) cp $1 ~/copias/$1 ;; .doc | * *.bak) # Tan slo como ejemplo de otras extensiones ;; ) * echo "$1 extensin desconocida" ;; esac 3. Ejemplo break y continue: este programa utiliza las rdenes break y continue para permitir al usuario controlar la entrada de datos. while true #bucle infinito do echo "Introduce un dato " read respuesta case "$respuesta" in "nada") # no hay datos break ;; "") # si es un retorno de carro se contina continue ;; *) # proceso de los datos echo "se procesan los datos" ;; esac done 4. Ejemplo de un men: while true do clear echo " Ver directorio actual...........[1] Copiar ficheros.................[2] Editar ficheros.................[3] Imprimir fichero................[4]

15

Salir del men..................[5]" read i case $i in 1) ls -l|more; read z ;; 2) echo "Introduzca [desde] [hasta]" read x y cp $x $y read x ;; 3) echo "Nombre de fichero a editar?" read x; vi $x ;; 4) echo "Nombre de fichero a imprimir?" read x lpr $x ;; 5) clear; break ;; esac done Este mismo ejercicio podra ser resuelto utilizando la orden select: select opcion in "Ver directorio "Copiar ficheros" \ "Editar ficheros" \ "Imprimir fichero" \ "Salir del men" do case $REPLY in 1) ls -l|more; read z ;; 2) echo "Introduzca [desde] read x y cp $x $y read x ;; 3) echo "Nombre de fichero read x; vi $x ;; 4) echo "Nombre de fichero read x lpr $x ;; 5) clear; break ;; esac done actual" \

[hasta]"

a editar?"

a imprimir?"

5. Este ejemplo lee dos nmeros del teclado e imprime su suma, (usando las rdenes read, printf y let).

16

#!/bin/bash printf "Introduzca un nmero \n" read numero1 printf "Introduzca otro nmero \n" read numero2 let respuesta=$numero1+$numero2 printf "$numero1 + $numero2 = $respuesta \n" 6. Escribir un guin shell que, dado el username de un usuario, nos devuelva cuntas veces esa persona est conectada. (Usa: who, grep, wc). #!/bin/bash veces=who | grep $1 | wc -l echo "$1 est conectado $veces veces" 7. Supongamos que queremos cambiar el sujo de todos los archivos *.tex a .latex. Haciendo mv *.tex *.latex no funciona, (por qu?), pero s con un guin shell. #!/bin/bash for f in *.tex do nuevo=$(basename $f tex)latex mv $f $nuevo done 8. Lo siguiente es un sencillo reloj que va actualizndose cada segundo, hasta ser matado con Ctrl-C: while true do clear; echo "==========="; date +"%r"; echo "==========="; sleep 1; done

7. EJERCICIOS PROPUESTOS. PRIMERA SESION


1. Haga un shell script llamado priult que devuelva los argumentos primero y ltimo que se le han pasado. Si se llama con: priult hola qu tal ests debe responder: El primer argumento es hola El ltimo argumento es ests Mejorar este shell script para tratar los casos en los que se llame con 0 o 1 argumento, indicando que no hay argumento inicial y/o nal. 2. Cree un shell script llamado fecha_hora que devuelva la hora y la fecha con el siguiente formato:

17

Son las hh horas, xx minutos del da dd de mmm de aaaa donde mmm representa las iniciales del mes en letra (ENE, FEB, MAR, ..., NOV, DIC). 3. Cree un shell script llamado tabla que a partir de un nmero que se le pasar como argumento obtenga la tabla de multiplicar de ese nmero. Si se llama con: tabla 5 debe responder: TABLA DE MULTIPLICAR DEL 5 ========================== 5 * 1 = 5 5 * 2 =10 ... 5 * 9 = 45 5 * 10 =50 Mejore el shell script para que se verique que slo se le ha pasado un argumento y que ste es un nmero vlido entre 0 y 10. 4. Haga un shell script llamado cuenta_tipos que devuelva el nmero de cheros de cada tipo que hay en un directorio, as como los nombres de estos cheros. Tendr un nico argumento (opcional) que ser el directorio a explorar. Si se omite el directorio se considerar que se trata del directorio actual. Devolver 0 (xito) si se ha llamado de forma correcta y 1 (error) en caso contrario. La salida ser de esta forma: La clasificacin de ficheros del directorio XXXX es: Hay t ficheros de texto: X1, X2, ... Xt Hay dv ficheros de dispositivo: X1, X2, ... Xdv Hay d directorios: X1, X2, ... Xd Hay e ficheros ejecutables: X1, X2, ... Xe (Pista: usar la orden le) 5. Cree un shell script llamado infosis que muestre la siguiente informacin: Un saludo de bienvenida del tipo: Hola usuario uuu, est usted conectado en el terminal ttt donde uuu y ttt son, respectivamente, el nombre de usuario y el terminal desde el que se ejecuta la orden. La fecha y la hora actuales, usando para ello el ejercicio nmero 3. Una lista con los usuarios conectados. Una lista de los procesos del usuario que se estn ejecutando en ese momento.

8. ENTRADA/SALIDA ESTNDAR Y REDIRECCIN


La losofa de UNIX/Linux es en extremo modular. Se preeren las herramientas pequeas que realizan tareas puntuales a las macro-herramientas que realizan todo. Para completar el modelo es necesario proporcionar el mecanismo para ensamblar estas herramientas en estructuras ms complejas. Esto se realiza por medio del redireccionamiento de las entradas y las salidas.

18

Todos los programas tienen por defecto una entrada estndar (teclado) y dos salidas: la salida estndar (pantalla) y la salida de error (pantalla). En ellos se puede sustituir el dispositivo por defecto por otro dispositivo. Con esto se consigue que los datos de la entrada estndar para un programa se puedan leer de un archivo, y los de la salida (estndar o error) se puedan enviar a otro archivo. La entrada estndar, la salida estndar y la salida de error se asocian a los programas mediante tres cheros con los cuales se comunican con otros procesos y con el usuario. Estos tres cheros son: stdin (entrada estndar): a travs de este descriptor de chero los programas reciben datos de entrada. Normalmente stdin est asociado a la entrada del terminal en la que est corriendo el programa, es decir, al teclado. Cada descriptor de chero tiene asignado un nmero con el cual podemos referirnos a l dentro de un script, en el caso de stdin es el 0. stdout (salida estndar): es el descriptor de chero en el que se escriben los mensajes que imprime el programa. Normalmente estos mensajes aparecen en la pantalla para que los lea el usuario. Su descriptor de chero es el nmero 1. stderr (salida de error): es el descriptor de chero en el que se escriben los mensajes de error que imprime el programa. Normalmente coincide con stdout. Tiene como descriptor de chero el nmero 2. Estos tres descriptores de chero pueden redireccionarse, consiguiendo comunicar unos procesos con otros, de forma que trabajen como una unidad, haciendo cada uno una tarea especializada, o simplemente almacenando los datos de salida en un chero determinado, o recibiendo los datos de entrada de un chero concreto. Hay varios operadores para redireccionar la entrada y las salidas de un programa de distintas maneras: > : redirecciona stdout a un chero, si el chero existe lo sobrescribe: $ who > usuarios.txt; less usuarios.txt >> : redirecciona stdout a un chero, si el chero existe aade los datos al nal del mismo. 2 > : redirecciona stdderr a un chero, si el chero existe lo sobrescribe: $ find / -type d -exec cat {} \; 2>errores.txt 2 >> : similar a >> pero para la salida de error. n>&m : redirecciona el descriptor de chero n al descriptor de chero m, en caso de que n se omita, se sobrentiende un 1 (stdout): $ cat file directorio >salida.txt 2>&1 # Redirecciona stdout al fichero salida.txt, y stderr a stdout < : lee la entrada estndar de un chero: $ grep cadena < fichero.txt # busca "cadena" dentro de fichero.txt | : redirecciona la salida estndar de una orden a la entrada estndar de otra orden: $ who | grep pilar ste ltimo tipo de redireccin es quizs el ms importante, puesto que se usa para integrar diferentes rdenes y programas, mediante la interconexin de sus entradas y salidas estndar. Ms concretamente, con una tubera o pipe (smbolo |) hay varias rdenes que se ejecutan sucesivamente, de manera que la salida estndar de la primera se enva a la entrada estndar de la siguiente, y as hasta que se ejecuta la ltima: $ orden1 | orden 2 | ... | orden n En la siguiente seccin veremos una serie de comandos cuyo principal cometido es procesar el texto que les llega por la entrada estndar, y volcar el resultado de dicho procesamiento en la salida estndar, en la forma de texto ltrado. Estos comandos, por tanto, se prestan al uso intensivo del mecanismo de redireccin a travs de tuberas.

19

9. RDENES INTERNAS DE BASH


Una orden interna del shell es una orden que el intrprete implementa y que ejecuta sin llamar a programas externos. Por ejemplo, echo es una orden interna de bash y cuando se llama desde un script no se ejecuta el chero /bin/echo. Algunos de las rdenes internas ms utilizadas son: echo: enva una cadena a la salida estndar, normalmente la consola o una tubera. Por ejemplo: echo El valor de la variable es $auxvar read: lee una cadena de la entrada estndar y la asigna a una variable, permitiendo obtener entrada de datos por teclado en la ejecucin de un guin shell: echo -n "Introduzca un valor para var1: " read var1 echo "var1 = $var1" La orden read puede leer varias variables a la vez. Tambin se puede combinar el uso de read con echo, para mostrar un prompt que indique qu es lo que se est pidiendo. Hay una serie de caracteres especiales para usar en echo y que permiten posicionar el cursor en un sitio determinado: \b: retrocede una posicin (sin borrar) \f : alimentacin de pgina \n: salto de lnea \t: tabulador Para que echo reconozca estos caracteres es necesario utilizar la opcin -e y utilizar comillas dobles: $ echo -e "Hola \t cmo ests?" hola como ests Una orden alternativa a echo para imprimir en la salida estndar es la orden printf. Su potencial ventaja radica en la facilidad para formatear los datos de salida al estilo del printf del lenguaje C. Por ejemplo, la orden: printf "Nmero: \t%05d\nCadena: \t%s\n" 12 Mensaje producira una salida como la siguiente: Nmero: 00012 Cadena: Mensaje

cd: cambia de directorio pwd: devuelve el nombre del directorio actual, equivale a leer el valor de la variable $PWD. pushd / popd / dirs: estas rdenes son muy tiles cuando un script tiene que navegar por un rbol de directorios: pushd: apila un directorio en la pila de directorios. popd: lo desapila y cambia a ese directorio. dirs: muestra el contenido de la pila. let arg [arg]: cada arg es una expresin aritmtica a ser evaluada (vese el apartado 10):

20

$ let a=$b+7 Si el ltimo arg se evala a 0, let devuelve 1; si no, devuelve 0. test: permite evaluar si una expresin es verdadera o falsa, vase el apartado La orden test. export: hace que el valor de una variable est disponible para todos los procesos hijos del shell. [.|source] nombre_chero argumentos: lee y ejecuta rdenes desde nombre_chero en el entorno actual del shell y devuelve el estado de salida de la ltima orden ejecutada desde nombre_chero. Si se suministran argumentos, se convierten en los parmetros cuando se ejecuta nombre_chero. Cuando se ejecuta un guin shell precedindolo de . o source, no se crea un shell hijo para ejecutarlo, por lo que cualquier modicacin en las variables de entorno permanece al nalizar la ejecucin, as como las nuevas variables creadas. exit: naliza la ejecucin del guin. Recibe como argumento un entero que ser el valor de retorno. Este valor lo recoger el proceso que ha llamado al guin shell. fg: reanuda la ejecucin de un proceso parado, o bien devuelve un proceso que estaba ejecutndose en segundo plano al primer plano. bg: lleva a segundo plano un proceso de primer plano o bien un proceso suspendido. wait: detiene la ejecucin hasta que los procesos que hay en segundo plano terminan. true y false: devuelven 0 y 1 siempre, respectivamente. Nota: El valor 0 se corresponde con true, y cualquier valor distinto de 0 con false.

10. EVALUACIN ARITMTICA


El shell permite que se evalen expresiones aritmticas, bajo ciertas circunstancias. La evaluacin se hace con enteros largos sin comprobacin de desbordamiento, aunque la divisin por 0 se atrapa y se seala como un error. La lista siguiente de operadores se agrupa en niveles de operadores de igual precedencia, se listan en orden de precedencia decreciente. -, + ~ ** *, /, % +, <<, >> <=, >= , <, > ==, != & ^ | && || expre?expre:expre =, +=, -=, *=, /=, %=, &=, ^=, |= <<=, >>= Menos y ms unarios Negacin lgica y de bits Exponenciacin Multiplicacin, divisin, resto Adicin, sustraccin Desplazamientos de bits a izquierda y derecha Comparacin Igualdad y desigualdad Y de bits (AND) O exclusivo de bits (XOR) O inclusivo de bits (OR) Y lgico (AND) O lgico (OR) Evaluacin condicional Asignacin: simple, despus de la suma, de la resta, de la multiplicacin, de la divisin, del resto, del AND bit a bit, del XOR bit a bit, del OR bit a bit, del desplazamiento a la izquierda bit a bit y del desplazamiento a la derecha bit a bit.

21

Por ejemplo, la siguiente orden muestra en pantalla el valor 64 $ echo $((2**6)) Se permite que las variables del shell acten como operandos: se realiza la expansin de parmetro antes de la evaluacin de la expresin. El valor de un parmetro se fuerza a un entero largo dentro de una expresin. Una variable no necesita tener activado su atributo de entero para emplearse en una expresin. Las constantes con un 0 inicial se interpretan como nmeros octales. Un 0x 0X inicial denota un nmero en hexadecimal. De otro modo, los nmeros toman la forma [base#]n, donde base es un nmero en base 10 entre 2 y 64 que representa la base aritmtica, y n es un nmero en esa base. Si base se omite, entonces se emplea la base 10. Por ejemplo: $ let a=6#10+1 $ echo el valor de a es $a El valor de a es 7 Los operadores se evalan en orden de precedencia. Las subexpresiones entre parntesis se evalan primero y pueden sustituir a las reglas de precedencia anteriores. Existen tres maneras de realizar operaciones aritmticas: 1. Con let lista_expresiones, como se ha dicho anteriormente, se pueden evaluar las expresiones aritmticas dadas como argumentos. Es interesante destacar que esta orden no es estndar, sino que es especca del bash. A continuacin se muestra un ejemplo de su uso: $ let a=6+7 $ echo El resultado de la suma es $a El resultado de la suma es: 13 $ let b=7%5 $ echo El resto de la divisin es: $b El resto de la divisin es: 2 $ let c=2#101\|2#10 $ echo El valor de c es $c El valor de c es 7 2. La orden expr sirve para evaluar expresiones aritmticas. Puede incluir los siguientes operadores: \(, \), \*, \\, \+, \-, donde el carcter \ se introduce para quitar el signicado especial que pueda tener el carcter siguiente. Por ejemplo: $ expr 10 \* \( 5 \+ 2 \) 70 $ i=expr $i - 1 #restar 1 a la variable i

3. Mediante $(( expresin )) tambin se pueden evaluar expresiones. Varios ejemplos de su uso seran: $ echo El resultado de la suma es $((6+7)) El resultado de la suma es: 13 $ echo El resto de la divisin es: $((7%5)) El resto de la divisin es: 2 $ echo El valor es $((2#101|2#10)) El valor de c es 7

22

11. LA ORDEN test


El comando test permite evaluar si una expresin es verdadera o falsa. Los tests no slo operan sobre los valores de las variables, tambin permiten conocer, por ejemplo, las propiedades de un chero. Principalmente se usan en la estructura if/then/else/ para determinar qu parte del script se va a ejecutar. Un if puede evaluar, adems de un test, otras expresiones, como una lista de rdenes (usando su valor de retorno), una variable o una expresin aritmtica, bsicamente cualquier orden que devuelva un cdigo en $?. La sintaxis de test puede ser una de las dos que se muestran a continuacin: test expresin [ expresin ] OJO! Los espacios en blanco entre la expresin y los corchetes son necesarios. La expresin puede incluir operadores de comparacin como los siguientes: Para nmeros: arg1 OP arg2, donde OP puede ser uno de los siguientes: -eq -ne -lt -le -gt -ge Igual a Distinto de Menor que Menor o igual que Mayor que Mayor o igual que

Es importante destacar que en las comparaciones con nmeros si utilizamos una variable y no est denida, saldr un mensaje de error. El siguiente ejemplo, al no estar la variable e denida, mostrar un mensaje de error indicando que se ha encontrado un operador inesperado. if [ $e -eq 1 ] then echo Vale 1 else echo No vale 1 fi Por el contrario, en el siguiente ejemplo, a la variable e se le asigna un valor si no est denida, por lo que s funcionara: if [ ${e=0} -eq 1 ] then echo Vale 1 else echo No vale 1 fi Para caracteres alfabticos o cadenas: -z cadena -n cadena cadena1 == cadena2 cadena1 != cadena2 cadena1 < cadena2 cadena1 > cadena2 Verdad si la longitud de cadena es cero. Verdad si la longitud de cadena no es cero. Verdad si las cadenas son iguales. Se puede emplear = en vez de ==. Verdad si las cadenas no son iguales. Verdad si cadena1 se ordena lexicogrcamente antes de cadena2 en la localizacin en curso. Verdad si cadena1 se clasica lexicogrcamente despus de cadena2 en la localizacin en curso.

23

En expresin se pueden incluir operaciones con cheros, entre otras: -e chero -r chero -w chero -x chero -f chero -s chero -d chero El chero existe. El chero existe y tengo permiso de lectura. El chero existe y tengo permiso de escritura. El chero existe y tengo permiso de ejecucin. El chero existe y es regular. El chero existe y es de tamao mayor a cero. El chero existe y es un directorio.

Adems se pueden incluir operadores lgicos y parntesis: -o -a ! \( \) OR AND NOT Parntesis izquierdo Parntesis derecho

A continuacin veremos distintos ejemplos de uso de la orden test, con el n de aclarar su funcionamiento. Uno de los usos ms comunes de la variable $#, es validar el nmero de argumentos necesarios en un programa shell. Por ejemplo: if test $# -ne 2 then echo "se necesitan dos argumentos" exit fi El siguiente ejemplo comprueba el valor del primer parmetro posicional. Si es un chero (-f) se visualiza su contenido; sino, entonces se comprueba si es un directorio y si es as cambia al directorio y muestra su contenido. En otro caso, echo muestra un mensaje de error. if test -f "$1" # es un fichero ? then more $1 elif test -d "$1" # es un directorio ? then (cd $1;ls -l|more) else # no es ni fichero ni directorio echo "$1 no es fichero ni directorio" fi Comparando dos cadenas: #! /bin/bash S1=cadena S2=Cadena if [ $S1!=$S2 ]; then echo "S1($S1) no es igual a S2($S2)" fi if [ $S1=$S1 ]; then echo "S1($S1) es igual a S1($S1)" fi

24

En determinadas versiones, esto no es buena idea, porque si $S1 o $S2 son vacos, aparecer un error sintctico. En este caso, es mejor: x$1=x$2 o $1=$2.

12. RDENES SIMPLES, LISTAS DE RDENES Y RDENES COMPUESTAS


12.1. rdenes simples
Una orden simple es una secuencia de asignaciones opcionales de variables seguida por palabras separadas por blancos y redirecciones, y terminadas por un operador de control. La primera palabra especica la orden a ser ejecutada. Las palabras restantes se pasan como argumentos a la orden pedida. Por ejemplo, si tenemos un shell script llamado programa, podemos ejecutar la siguiente orden: $ a=9 programa La secuencia de ejecucin que se sigue es: se asigna el valor a la variable a, que se exporta a programa. Esto es, programa va a utilizar la variable a con el valor 9. El valor devuelto de una orden simple es su estado de salida, 128+n si la orden ha terminado debido a la seal n.

12.2. Listas de rdenes


Un operador de control es uno de los siguientes smbolos: & && ; ;; ( ) | <nueva-lnea>

Una lista es una secuencia de una o ms rdenes separadas por uno de los operadores ;, &, &&, o ||, y terminada opcionalmente por uno de ;, &, o <nueva-lnea>. De estos operadores de listas, && y || tienen igual precedencia, seguidos por ; y &, que tienen igual precedencia. Si una orden se termina mediante el operador de control &, el shell ejecuta la orden en segundo plano en un subshell. El shell no espera a que la orden acabe, y el estado devuelto es 0. Las rdenes separadas por un ; se ejecutan secuencialmente; el shell espera que cada orden termine. El estado devuelto es el estado de salida de la ltima orden ejecutada. Los operadores de control && y || denotan listas Y (AND) y O (OR) respectivamente. Una lista Y tiene la forma: orden1 && orden2 orden2 se ejecuta si y slo si orden1 devuelve un estado de salida 0. Una lista O tiene la forma: orden1 || orden2 orden2 se ejecuta si y slo si orden1 devuelve un estado de salida distinto de 0. El estado de salida de las listas Y y O es el de la ltima orden ejecutada en la lista. Dos ejemplos del funcionamiento de estas listas de rdenes son: test -e prac.c || echo El fichero no existe test -e prac.c && echo El fichero s existe La orden test -e chero devuelve verdad si el chero existe. Cuando no existe devuelve un 1, y la lista O tendra efecto, pero no la Y. Cuando el chero existe, devuelve 0, y la lista Y tendra efecto, pero no la O. Otros ejemplos de uso son: sleep 1 || echo Hola sleep 1 && echo Hola # echo no saca nada en pantalla # echo muestra en pantalla Hola

25

Un ejemplo de lista de rdenes encadenadas con ; es: ls -l; cat prac.c; date Primero ejecuta la orden ls -l, a continuacin muestra en pantalla el chero prac.c (cat prac.c), y por ltimo muestra la fecha (date). El siguiente ejemplo muestra el uso del operador de control & en una lista: ls -l & cat prac.c & date & En este caso, ejecuta las tres rdenes en segundo plano.

12.3. rdenes compuestas


Las rdenes se pueden agrupar formando rdenes compuestas: { c1 ; ... ; cn; }: las n rdenes se ejecutan simplemente en el entorno del shell en curso, sin crear un shell nuevo. Esto se conocen como una orden de grupo. ( c1 ; ... ; cn ): las n rdenes se ejecutan en un nuevo shell hijo, se hace un fork. OJO! Es necesario dejar los espacios en blanco entre las rdenes y las llaves o los parntesis. Para ver de forma clara la diferencia entre estas dos opciones lo mejor es estudiar qu sucede con el siguiente ejemplo: Ejemplo #!/bin/bash cd /usr { cd bin; ls; } pwd 1.- Entrar al directorio /usr 2.- Listado del directorio /usr/bin 3.- Directorio actual: /usr/bin #!/bin/bash cd /usr ( cd bin; ls ) pwd 1.- Entrar al directorio /usr 2.- Listado del directorio /usr/bin 3.- Directorio actual: /usr

Resultado

Ambos grupos de rdenes se utilizan para procesar la salida de varios procesos como una sola. Por ejemplo: $ ( echo bb; echo ca; echo aa; echo a ) | sort a aa bb ca

13. FUNCIONES
Como en casi todo lenguaje de programacin, se pueden utilizar funciones para agrupar trozos de cdigo de una manera ms lgica, o practicar la recursin. Declarar una funcin es slo cuestin de escribir: function mi_func { mi_cdigo } Llamar a la funcin es como llamar a otro programa, slo hay que escribir su nombre.

26

13.1. Ejemplo de funciones


#! /bin/bash # Se define la funcin salir function salir { exit } # Se define la funcin hola function hola { echo Hola! } hola # Se llama a la funcin hola salir # Se llama a la funcin salir echo petete Tenga en cuenta que una funcin no necesita ser declarada en un orden especco. Cuando ejecute el script se dar cuenta de que: primero se llama a la funcin hola, luego a la funcin salir, y el programa nunca llega a la lnea echo petete.

13.2. Ejemplo de funciones con parmetros


#!/bin/bash function salir { exit } function e { echo $1 } e Hola e Mundo salir echo petete Este script es casi idntico al anterior. La diferencia principal es la funcin e, que imprime el primer argumento que recibe. Los argumentos, dentro de las funciones, son tratados de la misma manera que los argumentos suministrados al script. (Vase el apartado Variables y parmetros).

14. DEPURACIN
Una buena idea para depurar los programas es la opcin -x en la primera lnea: #!/bin/bash -x Como consecuencia, durante la ejecucin se va mostrando cada lnea del guin despus de sustituir las variables por su valor, pero antes de ejecutarla. Otra posibilidad es utilizar la opcin -v que muestra cada lnea como aparece en el script (tal como est en el chero), antes de ejecutarla: #!/bin/bash -v

27

Otra opcin es llamar al programa usando el ejecutable bash. Por ejemplo, si nuestro programa se llama prac1, se podra invocar como: $ bash -x prac1 $ bash -v prac1 Ambas opciones pueden ser utilizadas de forma conjunta: #!/bin/bash -xv $ bash -xv prac1

15. PATRONES DE USO DEL SHELL


En esta seccin se introducen patrones de cdigo para la programacin shell. Qu es un patrn? Un patrn es una solucin documentada para un problema tpico. Normalmente, cuando se programa en shell se encuentran problemas que tienen una muy fcil solucin, y a lo largo del tiempo la gente ha ido recopilando las mejores soluciones para ellos. Los patrones expuestos en este apartado han sido extraidos en su mayora de http://c2.com/cgi/wiki?UnixShellPatterns, donde pueden encontrarse algunos otros adicionales con tambin bastante utilidad.

15.1. Comprobacin de cadena vaca


La cadena vaca a veces da algn problema al tratar con ella. Por ejemplo, considrese el siguiente trozo de cdigo: if [ $a = "" ] ; then echo "cadena vacia" ; fi Qu pasa si la variable a es vaca? pues que la orden se convierte en: if [ = "" ] ; then echo "cadena vacia" ; fi Lo cual no es sintcticamente correcto (falta un operador a la izquierda de =). La solucin es utilizar comillas dobles para rodear la variable: if [ "$a" = "" ] ; then echo "cadena vacia" ; fi o incluso mejor, utilizar la construccin: if [ "x$a" = x ] ; then echo "cadena vacia" ; fi La x inicial impide que el valor de la variable se pudiera tomar como una opcin.

15.2. Uso de xargs


Muchos de los comandos de UNIX aceptan varios cheros. Por ejemplo, imaginemos que queremos listar todos los directorios que estn especicados en una variable: dirs="a b c" for i in $dirs ; do ls $i done Esto tiene un problema: lanza tres (o n) subshells, y ejecuta n veces ls. Este comando tambin acepta la sintaxis:

28

dirs="a b c" ls $dirs Una alternativa a esto cuando, por ejemplo, los argumentos estn en un chero, es utilizar xargs. Imaginemos que el chero directorios contiene los directorios a listar. El programa xargs acepta un conjunto de datos en la entrada estndar y ejecuta la orden con todos los parmetros aadidos a la misma: cat directorios | xargs ls Esto ejecuta el programa ls con cada lnea del chero como argumento.

15.3. Leer un chero lnea a lnea


A veces surge la necesidad de leer y procesar un chero lnea a lnea. La mayora de las utilidades de UNIX tratan con el chero como un todo, y aunque permiten separar un conjunto de lneas, no permiten actuar una a una. La orden read ya se vi para leer desde el teclado variables, pero gracias a la redireccin se puede utilizar para leer un chero. ste es el patrn: while read i ; do echo "Lnea: $i" # Procesar $i (lnea actual) done < $fichero El bucle termina cuando la funcin read llega al nal del chero de forma automtica.

15.4. Comprobar si una determinada variable posee un valor numrico vlido


Esto puede ser muy til para comprobar la validez de un argumento numrico. Por ejemplo: if echo $1 | grep -x -q "[0-9]\+" then echo "El argumento $1 es realmente un nmero natural." else echo "El argumento $1 no es un nmero natural correcto." fi

15.5. Leer argumentos opcionales de la lnea de comandos


Aunque puede hacerse mediante programacin convencional, el bash ofrece una alternativa interesante para esta tarea. Se trata de la orden getopts. La mejor manera de ver cmo se utiliza es con un ejemplo: while getopts t:r:m MYOPTION do case $MYOPTION in t) echo "El argumento para la opcin -t es $OPTARG" ;; r) echo "El ndice siguiente al argumento de -r es $OPTIND" ;; m) echo "El flag -m ha sido activado" ;; ?) echo "Lo siento, se ha intentado una opcin no existente"; exit 1; ;; esac done

29

Podemos ahora probar el efecto de una invocacin del guin como sta: ./guion -m -r hola -t adios -l La salida sera la siguiente: El flag -m ha sido activado El ndice siguiente al argumento de -r es 4 El argumento para la opcin -t es adios ./guion: opcin ilegal -- l Lo siento, se ha intentado una opcin no existente (El mensaje de la cuarta lnea es en realidad enviado a la salida estndar de error, por lo que si se quisiera se podra eliminar redireccionando con 2> a /dev/null). Como puede observarse, getopts comprueba si las opciones utilizadas estn en la lista permitida o no, y si han sido llamadas con un argumento adicional (indicado por los :) en la cadena de entrada t:r:m. Las variables $MYOPTION, $OPTIND y $OPTARG contienen en cada paso del bucle, respectivamente, el carcter con la opcin reconocida, el lugar que ocupa el siguiente argumento a procesar, y el parmetro correspondiente a la opcin reconocida (si sta iba seguida de : en la cadena de entrada).

16. EJEMPLOS DE GUIONES SHELL. SEGUNDA SESION


1. Programa que copia un chero en otro, controlando que el nmero de argumento sea exactamente dos. if [ $# != 2 ] then echo "utilice: copia [desde] [hasta]" exit 1 fi desde=$1 hasta=$2 if [ -f "$hasta" ] then echo "$hasta ya existe, desea sobreescribirlo (s/n)?" read respuesta if [ "$respuesta" != "s" ] then echo "$desde no copiado" exit 0 fi fi cp $desde $hasta 2. Programa que imprime el pantalla el contenido de un chero de datos, o el contenido de todos los cheros de un directorio. if test -f "$1" then pr $1|less elif test -d "$1" then cd $1; pr *|less else echo "$1 no es un fichero ni un directorio" fi

30

3. Programa que borra con conrmacin todos los cheros indicados como argumentos en la lnea de rdenes. #!/bin/bash while test "$1" != "" do rm -i $1 shift done 4. Programa que hace mltiples copias de cheros a pares. En cada iteracin desaparecen el primer y segundo argumento. while test "$2" != "" do echo $1 $2 cp $1 $2 shift; shift done if test "$1" != "" then echo "$0: el nmero de argumentos debe ser par y > 2" fi 5. Escribir un guin shell llamado ldir que liste los directorios existentes en el directorio actual. #!/bin/bash for archivo in * do test -d $archivo && ls $archivo done 6. Escribir un guin shell llamado ver que para cada argumento que reciba realice una de las siguientes operaciones: si es un directorio ha de listar los cheros que contiene, si es un chero regular lo tiene que mostrar por pantalla, en otro caso, que indique que no es ni un chero ni un directorio. #!/bin/bash for fich in $* do if [ -d $fich ] then echo "usando ls" ls $fich elif [ -f $fich ] then cat $fich else echo $fich no es ni un fichero ni un directorio fi done

31

7. Escribir un guin shell que solicite conrmacin si va a sobrescribir un chero cuando se use la orden cp. #!/bin/bash if [ -f $2 ] then echo "$2 existe. Quieres sobreescribirlo? (s/n)" read sn if [ $sn = "N" -o $sn = "n" ] then exit 0 fi fi cp $1 $2 8. Hacer un programa que ponga el atributo de ejecutable a los archivos pasados como argumento. for fich in $@ do if test -f $fich then chmod u+x $fich fi done

17. EJERCICIOS PROPUESTOS. SEGUNDA SESION


1. Cree un shell script llamado num_arg, que devuelva el nmero de argumentos con el que ha sido llamado. Devolver 0 (xito) si se ha pasado algn argumento y 1 (error) en caso contrario. Mejorar este shell de forma que muestre una lista de todos los argumentos pasados o bien que indique que no tiene argumentos: Los argumentos pasados son: ARGUMENTO NMERO 1: X1 ... ARGUMENTO NMERO N: XN No se han pasado argumentos 2. Cree un shell script llamado doble que pida un nmero por teclado y calcule su doble. Debe comprobar el nmero introducido y antes de terminar preguntar si deseamos calcular otro doble, en cuyo caso no terminar. Ejemplo: Introduzca un nmero para calcular el doble: 89 El doble de 89 es 178 Desea calcular otro doble (S/N)? 3. Cree un shell script llamado instalar al que se le pasarn dos argumentos: chero y directorio. El shell script debe copiar el chero al directorio indicado. Adems debe modicar sus permisos de ejecucin de forma que est permitido al dueo y al grupo del chero y prohibido al resto de usuarios. Antes de hacer la copia debe vericar los argumentos pasados, si se tiene permiso para hacer la copia, si el chero es de texto o ejecutable, etc. Devolver 0 (xito) si todo ha ido bien y 1 (error) en caso contrario. 4. Cree un guin shell llamado infouser que reciba un nico parmetro (el login de un usuario) y que muestre la siguiente informacin:

32

Login. Nombre completo del usuario. Directorio home. Shell que utiliza. Una lnea que indique si el usuario est actualmente conectado o no. Procesos pertenecientes a dicho usuario. La informacin a mostrar para cada proceso debe ser el PID y la lnea de rdenes que dio lugar a la creacin de dicho proceso. El guin debe comprobar: Si las opciones y parmetros son correctos. Si el usuario que se pasa como parmetro existe o no. Adems, debe permitir las siguientes opciones: -p: slo muestra informacin de procesos. -u: muestra toda la informacin excepto la referente a los procesos. --help: muestra informacin de ayuda (lo que hace el guin, su sintaxis y signicado de opciones y parmetros). Los cdigos de retorno deben ser: 0: xito. 1: no se ha respetado la sintaxis de la orden. 2: usuario no existe. Nota: parte de la informacin del usuario se puede obtener del chero /etc/passwd, en las salas de prcticas ejecutando la orden ypcat passwd. Pueden ser de utilidad las rdenes getopts y nger. 5. Cree un shell script llamado bustr, al que se le pase como parmetro una cadena y una lista de 0 a n nombres de chero. El shell script debe devolvernos los nombres de los archivos que contienen en su interior la cadena especicada. Para evitar errores slo se har con los archivos que sean regulares y sobre los que tengamos permiso de lectura. Por ejemplo: bustr cadena fichero1 fichero2 fichero 3 devolvera: La cadena "cadena" se ha encontrado en los siguientes ficheros: fichero2 fichero3 Cmo podra llamar a bustr para que hiciera la bsqueda en todos los cheros a partir de un directorio dado e incluyendo subdirectorios? Pista bustr cadena .... 6. Construir un guin shell en Linux con la siguiente sintaxis diffd [-i] directorio1 [directorio2] Funcin: debe mirar todos los nombres de chero contenidos en el directorio1 y en el directorio2 (a excepcin de los nombres de directorios) y mostrar las diferencias, es decir, mostrar el nombre de aquellos cheros que aparecen en uno de los directorios pero no en el otro, indicando para cada uno de ellos el directorio en el que se encuentra.

33

Parmetros: directorio1 y directorio2: directorios entre los que se hace la comparacin. Si se omite directorio2 (que es opcional) se entender que queremos comparar directorio1 con el directorio en el que nos encontremos al ejecutar diffd. Opciones: -i: invierte el funcionamiento de diffd haciendo que muestre los nombres de aquellos cheros que se encuentran en los dos directorios (es obvio que en este caso no hay que indicar el directorio en el que aparece el chero, pues aparece en ambos). 7. Hacer un guin shell llamado mirm que mueva al directorio ~/.borrados los cheros (nunca directorios) que se le indiquen como parmetros. Este guin shell viene acompaado por otro guin llamado limpiezad que se debe ejecutar en segundo plano y que cada 10 segundos compruebe si tiene que borrar cheros del directorio ~/.borrados en funcin del espacio ocupado en disco. Ambos guiones shell hacen uso de la variable de entorno MINLIBRE que indica el mnimo espacio en disco que debe quedar. De tal manera que una condicin que deben cumplir ambos guiones es que, tras su ejecucin, el espacio libre en disco (en bloques de 1K) debe ser igual o superior a MINLIBRE. En el caso de que, para cumplir dicha condicin, haya que borrar cheros de ~/.borrados, se seguir una poltica FIFO. Nota: basta con que ambos guiones funcionen para la particin en la que se encuentra el directorio personal del usuario. Adems, ambos guiones deben hacer uso del chero ~/.listaborrados que guardar, slo para cada chero presente en ~/.borrados, su ruta de acceso original. Mejora: debe permitirse el borrado de cheros con igual nombre. 8. Como complemento del ejercicio anterior, hacer un guin shell llamado recuperar que se utilizar para recuperar cheros borrados. Si se le pasa un nico parmetro se entender que se trata de un patrn y entonces mostrar todos los cheros de ~/.borrados que cumplan dicho patrn. Si se le pasan dos parmetros, el primero se entender como antes pero el segundo debe ser el nombre de un directorio y, en este caso, se recuperarn todos los cheros borrados que cumplan el patrn y se dejarn en el directorio indicado como segundo parmetro. Adems, este guin debe implementar tambin la opcin -o <patrn> que recuperar todos los cheros que cumplan <patrn> y los copiar a su posicin original, segn lo indicado por el chero ~/.listaborrados. Si el directorio original ya no existe, debe crearse siempre que se tenga permiso. Mejora: debe permitirse la recuperacin de cheros con igual nombre. 9. Cree un shell script llamado agenda al que se le pasar un argumento (opcional), que ser el nombre de chero que se usar para almacenar la informacin (si se omite el argumento, el chero ser agenda.dat, crendose en blanco si no existe). Cada lnea del chero tendr el siguiente formato: nombre:localidad:saldo:telfono Cuando se ejecute el shell script mostrar un prompt para poder introducir las distintas opciones disponibles: AGENDA (Introduzca opcin. h para ayuda) >> Las opciones que debe soportar son: h: mostrar ayuda de todas las opciones. q: para salir de la agenda. l: listar el chero de la agenda en columnas: ----------------- AGENDA ----------------------------Nombre Localidad Saldo Telfono -----------------------------Juan Ruiz Cartagena 134 968507765

34

Jaime Lpez Ana Martnez

Mlaga Madrid

95 945

952410455 914678984

on: ordenar la agenda por nombre ascendentemente. La ordenacin no se mostrar y quedar en el chero. Para ver la ordenacin habr que ejecutar l despus. os: ordenar la agenda por saldo descendentemente (ojo!, numricamente). La ordenacin no se mostrar y quedar en el chero. Para ver la ordenacin habr que ejecutar l despus. a: aadir una lnea. Para ello el shell script debe preguntar por el nombre, localidad, saldo y telfono, comprobando que ninguno de los campos quede en blanco. Una vez introducidos todos los datos de una nueva lnea, debe aadirse al nal del chero de la agenda. Como mejora, antes de introducir la nueva lnea se puede comprobar que no existe ninguna otra con el mismo nombre de persona. b: borrar una lnea. Para ello el shell script debe preguntar el nombre exacto de la persona correspondiente. Una vez introducido ste se debe eliminar la lnea o lneas que tengan ese nombre exactamente (pueden ser varias si en el punto anterior se permiten lneas con el mismo nombre). Antes de proceder con el borrado debe pedir conrmacin.

18. TERCERA SESION: EJERCICIOS DE EXAMENES (1/2)


1. Implementar un juego (adivina) en el que el ordenador debe adivinar el nmero del 1 al 10 que el usuario ha pensado. El programa muestra al principio un nmero al azar y debe pedir al usuario que le diga si el nmero mostrado es el correcto, es mayor o es menor. Dependiendo de la respuesta, el programa deber mostrar un nmero menor o mayor, o informar de que se ha encontrado el nmero. Por ejemplo: $ adivina El nmero es el 8? mayor, menor <- escrito por El nmero es el 5? mayor, correcto <- escrito por El nmero era el 5 !!

menor o correcto? el usuario menor o correcto? el usuario

As mismo, en su caso el programa deber detectar e informar al usuario de que ste ha hecho trampa (es decir, ha mentido en alguna de sus armaciones). 2. Escribir un guin llamado terminaminuto que reciba como parmetros una lista de comandos (posiblemente con argumentos), y que ejecute en segundo plano todos ellos. El guin deber entonces esperar hasta que llegue el siguiente minuto en punto y, para cada proceso lanzado que an no haya terminado, deber terminarlo de forma inmediata, mostrando un mensaje adecuado. Para los procesos que terminaron antes de dicho instante no es necesario que salga ningn mensaje. Ejemplo: $ date mar dic

5 14:09:20 CET 2006 kcalc "ls -la" "ps" gedit &

$ ./terminaminuto ...

Suponemos aqu que tanto el ls como el ps han terminado antes de que lleguen las 14:10:00, pero el kcalc y el gedit no. Entonces, justo al expirar el minuto actual (es decir, a las 14:10:00), deberan morir estos ltimos dos procesos, saliendo los siguientes mensajes por pantalla:

35

El proceso 8190 ha sido matado por expirar su minuto El proceso 8192 ha sido matado por expirar su minuto (Por supuesto, si 8190 y 8192 eran los PIDs del kcalc y el gedit, respectivamente). 3. Implementar un guin de bash (lsacum) que imprima en su salida estndar (por defecto, la pantalla) un listado de todos los cheros que se le pasan por la lnea de comandos, uno por lnea (como el que mostrara un ls -l lista-ficheros), pero con las siguientes particularidades: a) Deber mostrar slo aquellos argumentos correspondientes a cheros regulares (no directorios, ni enlaces, ni cheros especiales, etc.) b) Cada lnea mostrar nicamente los permisos del chero, el tamao acumulado (ver punto siguiente) y el nombre del chero, en ese orden. c) El campo de tamao de cada chero individual ser sustituido por el tamao acumulado de los cheros impresos hasta ese momento, incluyendo el actual. Ejemplo: si la salida de un comando ls -l normal en un directorio dado fuese, por ejemplo: $ ls -l -rw-r--r--rw-r--r--rw-r--r--rw-r--r-drwxrwxr-x 1 1 1 1 2 pgarcia pgarcia pgarcia pgarcia pgarcia profesor 470 dic 10 13:21 profesor 15339 dic 10 13:21 profesor 2076 dic 10 13:21 profesor 15311 dic 10 13:21 profesor 4096 dic 10 13:21 Makefile safe.c sender.c simple.c saved

Entonces una llamada lsacum s* a nuestro programa debera mostrar en su salida lo siguiente: $ lsacum s* -rw-r--r--rw-r--r--rw-r--r-15339 17415 32726 safe.c sender.c simple.c

Puesto que safe.c, sender.c y simple.c son cheros regulares, pero saved no (es un directorio), y puesto que 17415=15339+2076 y 32726=15339+2076+15311. 4. Cree un guin shell, llamado mediana, que para cada chero pasado como parmetro, calcule la mediana de la serie de nmeros enteros positivos contenidos en cada uno, a razn de uno por cada lnea. La sintaxis ser la siguiente: mediana <fichero1> [<fichero2>....<ficheroN>] Un ejemplo de resultado de ejecucin del comando sera (en el caso de que se introduzcan varios cheros): Fichero ------fichero1.txt ficherolargo.txt ficherolargo333.txt ... Mediana ------5 6 34

36

La denicin de mediana es: Punto medio de los valores despus de ordenarlos de menor a mayor, o de mayor a menor. Se tiene que 50 % de las observaciones se encuentran por arriba de la mediana y 50 % por debajo de ella. Por ejemplo, dado un conjunto impar de nmeros: 5, 3, 2, 1, 4: Los nmeros se ordenan: 1, 2, 3, 4, 5. La mediana sera el 3 ya que tiene dos nmeros por debajo de l (1 y 2) y dos nmeros por encima (4 y 5). Si el conjunto contuviese un nmero par de nmeros: 6, 3, 2, 7, 1, 5: Los nmeros se ordenan: 1, 2, 3, 5, 6, 7. En este caso hay dos nmeros en el centro (3 y 5). Entonces la mediana se calcula como la media aritmtica de esos dos nmeros. Es decir, la mediana sera 4 ((3+5)/2). 5. Implementar un guin de bash (monton) que imprima en su salida estndar (por defecto, la pantalla) un tringulo issceles formado por asteriscos de texto, simtrico verticalmente, y de altura igual al nmero que se le pasa como nico y obligatorio parmetro. Por ejemplo, si se teclea $ ./monton 5 el programa deber mostrar en su salida lo siguiente: * *** ***** ******* ********* El script deber comprobar que fue llamado con correccin (es decir, que tiene un parmetro y slo uno, y que ste es un entero mayor que cero). Obviamente, el programa deber funcionar para cualquier entero positivo (ya que, aunque la salida no cupiese en pantalla, podra redireccionarse sin problemas a un chero dado). 6. Escribir un guin shell llamado nombremaslargo que muestre el chero con el nombre ms largo de todos los que se encuentran en los directorios pasados como parmetros, o en alguno de sus subdirectorios. La sintaxis deber ser la siguiente: nombremaslargo dir1 [dir2] ... [dirN] Ojo, se tendrn en cuenta slo cheros, y se mostrar el chero que tenga el nombre ms largo, contando slo su nombre, y no la ruta completa. Eso s, en la salida deber mostrarse la ruta completa hasta el chero. En el caso de que dicho chero no sea nico (es decir, haya varios cheros con igual longitud, y sta sea la ms larga), el script deber mostrar en la salida los nombres de todos ellos. El guin deber comprobar que ha sido llamado con correccin (con una lista de al menos un directorio, y con ningn parmetro que no sea un directorio). Ejemplo: si suponemos una estructura de directorios como la siguiente: dir1/ |-- dir11 | |-- fich2.jpg | -- fichero1.jpg |-- dir12

37

| |-| --

-- fichero30.jpg dir123 -- fichero23.jpg fichero11.jpg

y ejecutamos el comando nombremaslargo dir1, la salida debera ser algo as como: $ nombremaslargo dir1 ./dir1/dir12/fichero30.jpg ./dir1/dir123/fichero23.jpg ./dir1/fichero11.jpg 7. Escribir un guin llamado ordpal que reciba como nico parmetro un nombre de chero de texto, y que escriba en la salida estndar, para cada lnea de dicho chero, la lista de palabras de la misma, todas en minsculas, separadas por espacios, ordenadas alfabticamente, sin repeticiones, y sin ningn tipo de carcter especial (puntuacin, etc.). El guin debe comprobar la correccin de la llamada (esto es, que recibe slo un parmetro, y que ste es un chero existente). Ejemplo: $ cat quijote.txt En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivia un hidalgo de los de lanza en astillero, adarga antigua, rocin flaco y galgo corredor. Una olla de algo mas vaca que carnero, salpicon las mas noches, duelos y quebrantos los sabados, lentejas los viernes, algun palomino de anyadidura los domingos, consumian las tres partes de su hacienda. $ ./ordpal quijote.txt acordarme cuyo de en ha la lugar mancha mucho no nombre quiero un adarga antigua astillero de en hidalgo lanza los que tiempo un vivia algo carnero corredor de flaco galgo mas olla que rocin una vaca y duelos lentejas las los mas noches quebrantos sabados salpicon y algun anyadidura consumian de domingos las los palomino tres viernes de hacienda partes su 8. Implementar una versin visual de du (duv) que muestre una barra indicando el tamao relativo de cada chero en un directorio dado como parmetro. Por ejemplo, si hay dos cheros en el directorio actual, uno de 100 bytes y otro de 200 bytes, la ejecucin duv . mostrara: $ duv . fichero1 fichero2 $ *********************** 33% ********************************************** 66%

El tamao de la barra es proporcional al porcentaje del tamao del directorio que corresponde al chero. La barra empezar en la columna 10, se truncarn los nombres de chero ms largos de 9 caracteres y llegar como mximo hasta la columna 70. Al nal de la barra se imprimir el porcentaje del directorio utilizado por el chero. Nota: Slo hay que mostrar los cheros existentes dentro del directorio que se pasa como parmetro, en el caso de que haya directorios contenidos en el directorio que se pasa como parmetro, stos no sern mostrados.

38

19. CUARTA SESION: EJERCICIOS DE EXAMENES (2/2)


1. Construir un script de nombre bisiesto que devuelva 0 si el ao introducido como parmetro era bisiesto y un -1 en caso contrario. Ejemplo de uso: $ bisiesto 2000 $ devolvera un 0 en $? (en pantalla nunca aparece nada). Nota: Un ao es bisiesto si febrero tiene da 29. 2. Cree un guin shell llamado capicuasinrev que devuelva como cdigo de salida 0 si el entero positivo dado como parmetro es capica y 1 en caso contrario. En la realizacin del ejercicio est prohibido usar la orden rev. Adems, es obligatorio que el guin shell compruebe que el nmero de parmetros y el entero dado son correctos; si no es as, debe devolver 2 como cdigo de salida y un mensaje de error que indique la sintaxis de la orden. Ejemplo: $ capicuasinrev 3113 $ echo $? 0 $ capicuasinrev 3112 $ echo $? 1 $ capicuasinrev 43,5 Sintaxis: capicuasinrev enteropositivo $ echo $? 2 $ 3. Cree un guin shell, llamado encolapro, con la siguiente sintaxis: encolapro [-t tiempo] proceso1 proceso2 proceso3 proceso4 ... El guin deber ejecutar en segundo plano, uno tras otro, todos los procesos indicados segn el orden establecido, pero sin que haya dos procesos al mismo tiempo en ejecucin. Para conseguirlo, ejecutar el primer proceso proceso1 y esperar los minutos indicados por tiempo. A continuacin comprobar si ese proceso ha terminado. Si ha terminado, ejecutar el siguiente, proceso2 y volver a esperar para lanzar proceso3. Sin embargo, si an no ha terminado, esperar de nuevo los minutos indicados, para despus realizar otra vez la comprobacin. Slo podr lanzar el siguiente proceso, cuando el anterior haya terminado, y la comprobacin la deber realizar segn los minutos indicados. El parmetro de tiempo es opcional, y en caso de que no se indique, su valor por defecto es de 60 segundos. Pista: Para esperar se puede usar la orden sleep. 4. Cree un guin shell llamado ordporlinlarga, que reciba como parmetros una lista de directorios, y que muestre como salida la lista de cheros regulares que cuelgan (recursivamente) de dichos subdirectorios, pero ordenada de mayor a menor por el nmero de caracteres que posee la lnea ms larga de cada uno de los cheros. Ejemplo: sean los cheros f1a.txt, f1b.txt, f2a.txt y f2b.txt, dentro de los directorios respectivos d1 (los dos primeros cheros) y d2 (para los dos ltimos):

39

$ cat d1/f1a.txt 123456789 123 1234567 1 $ 1 1 1 cat d1/f1b.txt 2 3 2 3 4 5 6 7 8 9 2 3 4 5 6 7

$ cat d2/f2a.txt abcde abcdefgh $ cat d2/f2b.txt Esta linea tiene

64

caracteres

contando

los

espacios.

Entonces, la ejecucin del comando sobre los directorios d1 y d2 debera producir la siguiente salida: $ ./ordporlinlarga d1 d2 ./d2/f2b.txt ./d1/f1b.txt ./d1/f1a.txt ./d2/f2a.txt Puesto que la lnea ms larga de f2b.txt tiene 64 caracteres, la de f1b.txt 17, la de f1a.txt 9, y la de f2a.txt 8. 5. Cree un guin shell, llamado psancestros, con la siguiente sintaxis: psancestros PID donde PID es un identicador de proceso. El guin debe comprobar que el parmetro PID existe, que es un nmero, y que corresponde a un proceso existente. A continuacin, tiene que imprimir la lista de PIDs desde el PID dado hasta el PID 0 (proceso raz). Para ello, necesita identicar el proceso padre de cada proceso, es decir, su PPID. Por ejemplo: $ ps PID TTY TIME CMD 5255 pts/0 00:00:01 bash 12527 pts/0 00:00:00 ps $ ./psancestros 5255 PID 5255-->5253-->1-->0 Nota: La opcin -l de ps permite identicar el PPID de un proceso. 6. Implementar un guin de bash (totalvsz) que imprima en su salida estndar (por defecto, la pantalla) un listado de todos los usuarios que se encuentran ejecutando algn proceso en el sistema, junto con un nmero indicando el tamao total de memoria virtual ocupado por todos los procesos de dicho usuario. Ejemplo: si la salida de un comando ps aux fuese, por ejemplo:

40

$ ps aux USER root root root daemon root pedro juan antonio juan antonio pedro PID 1 2 123 5220 5234 5387 5389 5390 5392 5399 6001 [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] VSZ 2912 0 1232 420 100 1716 15020 12721 8009 125 10 [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...]

Entonces una llamada totalvsz a nuestro programa debera mostrar en su salida lo siguiente: $ totalvsz USER root daemon pedro juan antonio TOTALVSZ 4244 420 1726 23029 12846

7. Cree un guin shell llamado buscapalabras con la siguiente sintaxis: buscapalabras ficherodepalabras ficherodebusqueda Donde ficherodepalabras es el nombre de un chero que contiene una lista de palabras, una por lnea, y ficherodebusqueda ser un chero de texto donde se buscarn las palabras indicadas en ficherodepalabras. Como resultado se mostrar, por cada palabra, el nmero de lneas donde aparece la palabra en el chero indicado. El resultado deber estar ordenado de forma creciente por el nmero de apariciones de las palabras. Ejemplo: $ cat palabras.txt Mancha de lugar DE $ cat citaQuijote.txt "En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho vivia un hidalgo de los de lanza en astillero, ..." $ buscapalabras palabras.txt citaQuijote.txt Mancha 1 lugar 1 de 4 $

41

Nota: A la hora de procesar las palabras del chero ficherodepalabras no se distinguir entre maysculas y minsculas y la misma palabra en distinta lneas se considerar una nica palabra. 8. Cree un guin shell, llamado quiniela, que nos genere de forma aleatoria una quiniela simple de 1 apuesta, es decir un resultado para cada partido. Cuando ejecute el script: quiniela El resultado debe ser similar al siguiente: 1.- 1 2.- X 3.- X ... 14.2 Observese la alineacin de los nmeros y que los todos los resultados del mismo tipo estn en la misma columna. Nota: La variable de entorno $RANDOM de bash puede utilizarse para generar un nmero aleatorio entero entre 0 y 32767, distinto cada vez que es invocada.

20. BIBLIOGRAFA
Pgina de manual del intrprete de rdenes bash. http://www.insflug.org/bajar.php3?comoID=121. Programacin en BASH - COMO de introduccin. Mike G. (traducido por Gabriel Rodrguez). http://c2.com/cgi/wiki?UnixShellPatterns. Unix shell patterns, J. Coplien et alt. http://learnlinux.tsf.org.za/courses/build/shell-scripting. Shell scripting, Hamish Whittal.

42