Está en la página 1de 27

Programacin con bash

ndice de contenidos
1. Primer contacto 2. Desvo de la salida y la entrada de los comandos 3. Nombres de ficheros y metacaracteres 4. Comillas y caracteres de esca e 5. "#beras de com#nicaci$n% i es !. &#stit#ci$n de comandos or s# salida '. &ec#encias de comandos (. )* resiones (.1. ,ariables (.2. ,ariables es eciales (.3. )* resiones aritm-ticas (.4. )l comando test +. .#tinas +.1. /lgo ms sobre los armetros +.2. ,alor de retorno +.3. ,ariables locales +.4. 1ibliotecas de r#tinas 10. &entencias de control 10.1. case ... in ... esac 10.2. if ... then ... fi 10.3. for ... do ... done 10.4. 2hile ... done 10.5. #ntil ... done Pg. 3 Pg. 3 Pg. 5 Pg. ! Pg. ! Pg. ' Pg. ( Pg. + Pg. + Pg. 13 Pg. 14 Pg. 1! Pg. 1' Pg. 1( Pg. 20 Pg. 21 Pg. 22 Pg. 22 Pg. 23 Pg. 23 Pg. 24 Pg. 25 Pg. 25!

3n shell es #n rograma a medio camino entre el #s#ario y el sistema o erativo. )n 3N45 hay m#ltit#d de shells6 ero 7#i8 #no de los ms frec#entes es el Bourne Shell y s# me9ora Bourne Again Shell (bash). Cada #no de los shells 7#e e*isten tienen artic#laridades 7#e lo hacen :nico6 ero tambi-n m#chas similit#des 7#e nos ermiten6 #na ve8 a rendido #no6 traba9ar con los dems sin demasiados roblemas. )n n#estro caso6 traba9aremos con el Bourne Again Shell (bash)6 ya 7#e es el shell 7#e trae Guadalinex or defecto. )l desarrollo de esta #nidad didctica o lecci$n est ensado ara ersonas 7#e han tenido contacto con alg:n ti o de leng#a9e de rogramaci$n y 7#e conoce los conce tos de variable6 r#tina6 sentencia de control6 mbitos locales de declaraci$n de identificadores6 etc.

1. Primer contacto
)n el momento en el 7#e #na ersona obtiene #na c#enta en #na m7#ina 3N456 el administrador le asigna #na shell de traba9o 7#e ser el 7#e le dar la bienvenida cada ve8 7#e inicie #na sesi$n en esa m7#ina. Para averig#ar c#l es el shell de traba9o 7#e le ha asignado s# administrador tan s$lo tiene 7#e e9ec#tar en el terminal el sig#iente comando 7#e m#estra en antalla el contenido de la variable $SHELL. )sta es la variable es la 7#e el sistema #tili8a de forma estndar ara g#ardar el nombre del shell de traba9o.
$ echo $SHELL

&i no a arece la cadena /bin/bash 7#e identifica al deber cambiar s# shell de traba9o ara oder contin#ar esta lecci$n. Para ello tan s$lo debe e9ec#tar el comando chsh. /l hacerlo a arecer #na lista con los nombres com letos de todos los shell dis onibles en s# sistema e instr#cciones aso a aso 7#e le ermitirn cambiarlo de #na forma m#y sencilla. / lo largo de toda la lecci$n iremos mostrando n#merosos e9em los 7#e nos 3

ermitirn il#strar cada #no de los conce tos est#diados. )n alg#nos de ellos al final de alg#nas lneas a arece #n te*to en castellano recedido del smbolo ;. &e trata de comentarios 7#e bash shell ignora or com leto.

2. Desvo de la salida y la entrada de los comandos


)l bash shell ermite desviar la entrada y la salida de todos los comandos de forma 7#e estos #edan leer o escribir s#s datos en #n fichero6 en la antalla6 en #na lnea de com#nicaciones o en c#al7#ier otro dis ositivo sin 7#e sea reciso cambiar #na sola lnea del c$digo f#ente. Para desviar6 or e9em lo6 la salida del comando ls a #n fichero llamado lst basta con teclear el sig#iente comando%
$ ls -F > lst

)ste comando crea rimero el fichero lst y a contin#aci$n e9ec#ta ls6 ero desviando toda la salida 7#e rod#8ca hacia este fichero. "ambi-n es osible desviar la salida de #n comando a<adi-ndola a #n fichero ya e*istente. Por e9em lo6 si 7#isi-ramos a<adir al fichero anterior la frase =estos eran mis ficheros=6 bastara con teclear el sig#iente comando%
$ echo "estos eran mis ficheros" >> lst

&i ahora mostramos en antalla el contenido de lst obtendramos el sig#iente res#ltado%


$ cat lst a.c b.c buf.c copia/ f1.dat f2.dat f3.dat estos eran mis ficheros

>a entrada estndar tambi-n se #ede desviar. Por e9em lo6 si deseamos enviar al #s#ario juan el fichero anterior6 odemos indicar al comando mail 7#e lea el te*to a enviar desde este fichero de la sig#iente forma%
$ mail juan < lst

"ambi-n es osible desviar la entrada #sando el smbolo <<6 ero en este caso el res#ltado es diferente. C#ando tecleamos #n comando de la forma
$ cmd << palabra

)l shell crea #n fichero tem oral en el 7#e introd#ce todas las lneas 7#e lea de la 4

entrada estndar hasta encontrar #na 7#e contenga tan s$lo la alabra indicada. / contin#aci$n e9ec#ta el comando desviando s# entrada a trav-s ese fichero tem oral. )n cierto modo6 algo como
$ mail juan << fin Hola Juan, te he enviado el listado de mis ficheros fin

es e7#ivalente a la sec#encia de comandos


$ echo "Hola Juan, te he enviado el listado de mis ficheros" > tmp $ mail juan < tmp $ rm tmp

)ste ti o de desvo se #tili8a de forma casi e*cl#siva en los rogramas 7#e constr#yamos en el leng#a9e del shell. )n sesiones interactivas rcticamente no se #tili8a.

3. Nombres de ficheros y metacaracteres


"odos los shell de 3N45 ermiten el #so de metacaracteres ara re resentar de forma sim lificada con9#ntos ms o menos am lios de nombres de ficheros c#yos nombres enca9an en #n cierto atr$n. / contin#aci$n se m#estran los c#atro metacaracteres e*istentes%

*6 7#e conc#erda con c#al7#ier cadena de caracteres6 incl#ida la cadena vaca. ?6 7#e conc#erda tan s$lo con #n carcter. [a1a2 ... an]6 7#e conc#erda con c#al7#iera de los caracteres entre los corchetes. )s osible es ecificar #n rango se arando el carcter inicial y final del mismo mediante #n g#i$n. Por e9em lo [a-z] enca9a en c#al7#ier letra min:sc#la ?e*ce t#ando la <@. [!a1a2 ... an]6 7#e conc#erda con c#al7#ier carcter 7#e no a are8ca entre los corchetes. Como en el caso anterior6 es osible es ecificar rangos de caracteres #sando el g#i$n.

/ contin#aci$n se m#estran varios e9em los de #so de los metacaracteres%


$ ls -FR a.c b.c buf.c copia/ f1.dat f2.dat f3.dat ./copia: a.c b.c buf.c f1.dat f2.dat f3.dat $ # ficheros cuyo nombre terminan en .c $ls *.c a.c b.c buf.c

$ # ficheros .c cuyo nombre base tiene un carcter $ ls ?.c a.c b.c $ # ficheros cuyo nombre incluye al menos un dgito $ ls *[0-9]* f1.dat f2.dat f3.dat $ # ficheros .c con nombre base de un carcter bajo el directorio actual $ ls */?.c copia/a.c copia/b.c $ # ficheros cuyo nombre tiene tres caracteres y el central es un punto $ # en el directorio actual y en los inmediatamente inferiores $ ls ?.? */?.? a.c b.c copia/a.c copia/b.c

)n el e9em lo hemos mostrado diversos #sos de los atrones con el comando ls6 ero se #eden #tili8ar casi en c#al7#ier l#gar y siem re 7#e el shell los enc#entra los s#stit#ye de forma a#tomtica or la lista com leta de nombres de ficheros 7#e enca9an en el mismo. Por e9em lo%
$ echo "Estos son los ficheros de mi directorio: " * Estos son los ficheros de mi directorio: a.c b.c c.c

4. Comillas y caracteres de escape


"al y como hemos odido ver hasta ahora6 el shell reserva ara #so ro io ciertos caracteres. /lg#nos de ellos son oco com#nes en la escrit#ra6 ero otros son de #so frec#ente y se necesita del alg:n mecanismo 7#e nos ermita im edir al shell los inter rete con s# significado es ecial. )l rimer mecanismo consiste en escribir esos caracteres entre comillas sim les o dobles. )n el rimer caso6 todo lo 7#e escribamos entre comillas se inter retar literalmente6 esto es6 si a arece #n * se inter retar como el carcter asterisco y no como la lista de todos los nombres ficheros en el directorio act#al. )n el seg#ndo caso tan s$lo se inter retarn literalmente los metacaracteres6 mientras 7#e las variables sern s#stit#idas or s#s valores. De momento tan s$lo conocemos la variable $SHELL 7#e nos ermite conocer c#l es el nombre de n#estro shell de traba9o6 ero ser s#ficiente ara il#strar el com ortamiento de las comillas.
$ ls f.dat main.c $ echo $SHELL * $SHELL * $ echo "$SHELL *" /bin/bash * $ echo $SHELL * /bin/bash a.c b.c buf.c copia f1.dat f2.dat f3.dat

>as comillas ermiten delimitar #na cadena de te*to. &i tan s$lo 7#eremos inter retar literalmente #n carcter odemos recederlo de #na barra invertida.
$ ls f.dat main.c $ echo \$SHELL \* $SHELL * $ echo "\$SHELL \*" $SHELL * $ echo $SHELL * /bin/bash a.c b.c buf.c copia f1.dat f2.dat f3.dat

5. Tuberas y comunicaciones: pipes


&it#aciones en las 7#e la salida de #n comando se #tili8a como la entrada de otro son m#y frec#entes en la rctica. Por e9em lo6 s# ongamos 7#e deseamos obtener #n listado ordenado alfab-ticamente con informaci$n acerca de todos los #s#arios conectados act#almente en la m7#ina. &abemos 7#e el comando who ermite obtener la informaci$n acerca de los #s#arios conectados y 7#e sort #ede ordenarla alfab-ticamente. 3na osible sol#ci$n es%
$ who > tmp $ sort < tmp usuario1 :0 Sep 09 19:53 usuario2 :1 Sep 09 15:45 $ rm tmp

)n este caso hemos #sado el fichero tmp ara g#ardar de forma tem oral la informaci$n ro orcionada or who antes de #sar el comando sort. 3na forma sim lificada de hacer esto es #sar t#beras6 tal y como se m#estra a contin#aci$n%
$ who | sort usuario1 :0 Sep 09 19:53 usuario2 :1 Sep 09 15:45

)l efecto es similar a la creaci$n de #n archivo tem oral6 con la :nica diferencia de 7#e el #so de las t#beras es m#cho ms eficiente. 3no de los roblemas de las t#beras es 7#e el #s#ario no #ede observar c#l es la informaci$n 7#e corre a trav-s de ellas. Para conseg#irlo se #ede #sar el comando tee f 7#e toma s# entrada estndar y la v#elca en #n fichero de nombre f al mismo tiem o 7#e en s# salida estndar. De esta forma6 el comando%
$ who | tee who.txt | sort

'

usuario1 :0 Sep 09 19:53 usuario2 :1 Sep 09 15:45

m#estra efectivamente la informaci$n ordenada alfab-ticamente acerca de los #s#arios conectados6 ero tambi-n la v#elca el listado ?sin ordenar@ en el fichero who.txt.
$ cat who.txt usuario2 :1 Sep 09 15:45 usuario1 :0 Sep 09 19:53

6. Sustitucin de comandos por su salida


>as t#beras nos ro orcionan #n mecanismo sencillo ara #tili8ar la salida de #n comando como entrada de otro. Pero e*isten m#ltit#d de ocasiones en las 7#e lo 7#e realmente necesitamos es #sar la salida de #no o varios comandos como armetros ara e9ec#tar otro comando6 no como s# entrada estndar. )n estos casos es osible #tili8ar la t-cnica conocida como s#stit#ci$n de #n comando or s# salida. )sto se consig#e e9ec#tando el comando entre tildes graves ?`@ y toda la informaci$n 7#e m#estre en s# salida estndar s#stit#ir a la cadena entre las tildes graves. Por e9em lo%
$ echo La fecha de hoy es date La fecha de hoy es vie sep 09 20:08:54 CEST 2005

)l comando date se ha e9ec#tado entre tildes graves6 or lo 7#e todo a7#ello 7#e rod#8ca en s# salida estndar es ca t#rado y colocado en s# l#gar. )s osible combinar tantas s#stit#ciones de comando como sean recisas. Por e9em lo6 el sig#iente comando m#estra la fecha act#al y el n:mero de #s#arios conectados en la m7#ina.
$ echo Hoy es date y hay who | wc -l usuarios Hoy es vie sep 09 20:08:54 CEST 2005 y hay 2 usuarios

)ste ti o de s#stit#ciones res#ltan m#y otentes y :tiles en m#ltit#d de ocasiones. Por e9em lo6 si 7#isi-ramos editar todos a7#ellos ficheros .txt 7#e contengan la alabra fecha bastara con e9ec#tar el sig#iente comando%
$ vi grep -l fecha *.txt

grep -l fecha *.txt m#estra en s# salida estndar el nombre de todos a7#ellos ficheros en el directorio act#al terminados en .txt 7#e contienen la cadena de caracteres (

fecha. Por lo tanto6 escribir este comando es e7#ivalente a escribir detrs de vi los nombres de todos esos ficheros.

7. Secuencias de comandos
Para e9ec#tar varios comandos #no detrs de otro6 la forma ms sencilla es escribirlos en varias lneas6 introd#ciendo #n retorno de carro al final de cada #no. Pero e*isten sit#aciones en las 7#e tenemos 7#e escribir necesariamente dos comandos en #na misma lnea. Por e9em lo s# ongamos 7#e el comando morosos rod#ce #n listado con las direcciones de correo electr$nico de todos los morosos de n#estra em resa en el fichero morosos.txt. &i deseamos enviar #na carta a todos ellos odemos #sar la sig#iente s#stit#ci$n de comando%
$ morosos $ mail cat morosos.txt < carta

morosos no rod#ce la lista de morosos en s# salida estndar6 sino en el fichero morosos.txt6 or lo 7#e #na ve8 e9ec#tado el comando es necesario #sar cat ara obtener las direcciones de la lista. )sto e*ige e9ec#tar en sec#encia dos comandos y ara ello odemos #sar el #nto y coma como se arador en ve8 de teclear dos lneas.
$ morosos; mail cat morosos.txt < carta

Pero ensemos or #n momento en 7#e el comando morosos falla or c#al7#ier ra8$n y no rod#ce el fichero morosos.txt. )n este caso el comando cat fallara tambi-n al no encontrarlo o bien leera #n ficheros de morosos res#ltado de #na e9ec#ci$n revia del comando. )s evidente 7#e tan s$lo debe enviarse la carta si el rograma de morosos se ha e9ec#tado correctamente. )n estos casos odemos #sar la com osici$n sec#encial de comandos con el smbolo &&. cmd1 && cmd2 && && cmdn e9ec#ta en sec#encia los comandos indicados hasta 7#e falle alg#no de ellos. )n ese caso los comandos 7#e vienen a contin#aci$n no se e9ec#tan. De esta forma6 el comando 7#e b#scbamos ara enviar n#estras cartas a los morosos sera el sig#iente%
$ morosos && mail cat morosos.txt < carta

Atra osibilidad ara e9ec#tar comandos en sec#encia es se arndolos con el smbolo ||. cmd1|| cmd2 || || cmdn e9ec#ta los comandos es ecificados hasta 7#e #no de ellos no falle. De esta forma si 7#eremos mostrar #n mensa9e de error en caso de 7#e no se haya odido enviar la carta a todos los morosos6 odemos #sar el sig#iente +

comando%
$ ( morosos && mail cat morosos.txt < carta ) || echo Error

B9ese en 7#e hemos #tili8ado ar-ntesis ara agr# ar los comandos delante del smbolo ||. )stos hacen 7#e los comandos en s# interior se agr# en y se e9ec#ten como si de #n :nico comando se tratase. De esta forma si c#al7#iera de los dos falla a arecer en antalla el mensa9e Error.

8. Expresiones
1ash shell ro orciona #n r#dimentario leng#a9e de e* resiones con el 7#e odemos llevar a cabo las o eraciones aritm-ticas6 l$gicas o de cadena ms com#nes. )n esta secci$n las est#diaremos todas em e8ando or las ms sencillas de todas6 las variables.

8.1 Variables
/l ig#al 7#e c#al7#ier otro leng#a9e de rogramaci$n6 los rogramas escritos en bash shell #eden #sar variables ara almacenar informaci$n de forma tem oral. >a :nica diferencia entre estas variables y las de c#al7#ier otro leng#a9e de rogramaci$n de #so habit#al es 7#e todas se tratan como si de cadenas de caracteres se tratase y adems #eden contener datos de longit#d arbitraria. )sto significa 7#e a#n7#e #na variable contenga el valor 1236 el shell inter retar ese valor como #na cadena de tres caracteres6 n#nca como #n n:mero entero. )*isten dos ti os rinci ales de variables6 las de entorno y las locales. No e*iste diferencia alg#na entre ellas desde el #nto de vista de s# #so. >a :nica diferencia es 7#e c#ando #n shell invoca a otro6 las rimeras son heredadas de forma a#tomtica or el shell hi9o6 mientras 7#e las del seg#ndo gr# o no. Por e9em lo6 s# onga 7#e en s# shell de traba9o act#al las variables PATH y PWD son variables de entorno y L1 y L2 son variables locales. )l bash shell define a#tomticamente alg#nas variables de entorno 7#e son de gran inter-s. / contin#aci$n se m#estran las ms im ortantes% Nombre HOME Significado Nombre del directorio con la c#enta del #s#ario

10

PATH

3n con9#nto de nombres de directorio se arados or el smbolo : en los 7#e b#scar los comandos Nombre del #s#ario Nombre com leto del shell 7#e se est #tili8ando "i o de terminal 7#e se est #tili8ando

LOGNAME SHELL TERM

"ambi-n define de forma a#tomtica diversas variables locales 7#e toman valores or defecto cada ve8 7#e se e9ec#ta #na co ia del shell >a sig#iente tabla recoge las ms im ortantes% Nombre PPID PWD OLDPWD Significado N:mero identificador del roceso adre Nombre del directorio de traba9o act#al Nombre del anterior directorio de traba9o antes de e9ec#tar or :ltima ve8 el comando cd 3n n:mero entero generado al a8ar Cadena 7#e resenta el shell cada ve8 7#e solicita #n comando Cadena 7#e resenta el shell cada ve8 7#e solicita la contin#aci$n de #n comando 7#e oc# a varias lneas de antalla

RANDOM PS1 PS2

8.1.1 Definicin y consulta


)n bash shell no es necesario declarar las variables. Para introd#cir #na n#eva tan s$lo es necesario asignarle #n valor #tili8ando la sig#iente sinta*is ?f9ese en 7#e no e*iste ning:n es acio en blanco al rededor del signo =@%
$ mi_nombre=juan $ mi_maquina=bicho.es

Para la cons#lta de variables es necesario receder el nombre de las variables del signo $. Por e9em lo%
$ mi_direccion=$mi_nombre@$mi_maquina $ mi_cuenta=file://$mi_maquina/$LOGNAME

11

$ echo $mi_direccion juan@bicho.es $ echo mi_direccion mi_direccion $ mi_otra_direccion=mi_nombre@mi_maquina $echo $mi_otra_direccion mi_nombre@mi_maquina

"odas las variables 7#e definamos #sando este m-todo son variables locales6 y or lo tanto no son heredadas or los shells 7#e se e9ec#ten a artir del act#al. Para definir #na variable de entorno se debe #sar el comando export. Por e9em lo%
$ export mi_direccion=$mi_nombre@$mi_maquina

crea #na variable de entorno llamada mi_direccion 7#e ser heredada or c#al7#ier subshell. C#al7#ier variable local #ede convertirse en variable de entorno #sando el comando export variable. Para ver la lista de todas las variables de entorno se #ede #sar el comando export sin ning:n armetro.

8.1.2 Consulta avanzada de variables


/nte oner #n $ al nombre de #na variable es el modo de cons#lta ms sencillo ara las variables6 ero e*isten otras ms com le9os 7#e se recogen en la sig#iente tabla% Patrn ${v} ${#v} ${#v[*]} ${v-c} ${v=c} Significado 4d-ntico a $v. &e #tili8a en los casos de ambigCedad N:mero de caracteres de la cadena 7#e contiene v N:mero de elementos del vector v &i v ha sido definida s# valor6 en otro caso c &i v ha sido definida s# valor6 en otro caso le asigna ahora el valor c &i v ha sido definida c6 en otro caso la cadena vaca

${v+c}

12

Patrn ${v?c}

Significado &i v ha sido definida s# valor6 en otro caso se m#estra en la salida de errores la cadena c y termina la e9ec#ci$n del shell script &imilar a los modos de cons#lta en 7#e no a arece el smbolo :6 ero a las variables adems de estar definidas se les e*ige 7#e el valor 7#e contienen no sea la cadena vaca. )l valor de la variable6 ero eliminando del mismo todos los caracteres iniciales 7#e enca9en en el atr$n p. &i #samos # se elimina la s#bcadena ms corta y si #samos ## se elimina la ms larga. &imilar a ${v#p} y D{v##p} ero eliminando la s#bcadena or el final.

${v:+c} ${v:=c} ${v:-c} ${v:?c}

${v#p} ${v##p}

${v%p} ${v%%p}

/ contin#aci$n se m#estra #n e9em lo de #so de todos estos modos avan8ados de acceso a las variables.
$ mi_nombre=juan $ mi_maquina=bicho.es $ mi_direccion=$mi_nombre@$mi_maquina $ echo ${#mi_nombre} 4 $ cd trash $ echo $PWD ${#PWD} /home/juan/trash 16 $ echo $HOME /home/juan $ echo ${PWD#$HOME/} trash $ ls f.dat $ mi_fichero=f.dat $ cp $mi_fichero ${mi_fichero%.dat}.bak $ ls f.dat f.bak

8.1.3 Vectores
13

Bash shell ofrece la osibilidad de #sar vectores de valores #tili8ando #na sinta*is con corchetes ara los s#bndices. >a :nica limitaci$n en este caso es 7#e el ndice de los mismos debe estar entre 0 y 5116 or lo 7#e tan s$lo son osibles vectores de hasta 512 com onentes. Para crear #n vector basta con asignar #n valor a #no de s#s com onentes. >os restantes se irn creando de forma dinmica conforme se vayan necesitando. Para acceder a #na com onente artic#lar se #sa la sinta*is ${v[i]}. Por e9em lo%
$ amigos[0]=Juan $ amigos[1]=Lus $ amigos[2]=Mara $ amigos[3]=Ana $ echo ${amigos[0]} est casado con ${amigos[2]} Juan est casado con Mara $ echo Tengo ${#amigos[*]} en la agenda Tengo 4 amigos en la agenda $ Mis amigos son ${amigos[*]} Mis amigos son Juan Lus Mara Ana

>a notaci$n ${v[*]} se #tili8a ara acceder a todos los elementos del vector de forma con9#nta.

8.2 Variables especiales


)l bash shell ermite el #so de alg#nas variables es eciales 7#e se recogen en la sig#iente tabla. &# valor no se #ede cambiar de la forma 7#e hemos visto hasta ahora y generalmente s$lo se #tili8an en los rogramas escritos en shell script6 n#nca c#ando el shell se #tili8a de forma interactiva. Nombre $$ $0 $1..$9 $? $# $* Significado Nmero de proceso del shell script en el que se est utilizando Nombre completo del shell script en que se est utilizando $n hace referencia al nE-simo arg#mento de la lnea de comandos )l c$digo de retorno del :ltimo comando e9ec#tado N:mero de arg#mentos >a lista de todos los arg#mentos

14

"odas las variables 7#e hemos mostrado son es eciales en el sentido de 7#e no es osible darles #n valor #tili8ando los m-todos 7#e hemos est#diado hasta el momento. De todas formas las variables de la forma $i son #na e*ce ci$n6 ya 7#e es osible cambiar s#s valores a vol#ntad6 a#n7#e #tili8ando el comando set y no los mecanismos habit#ales. C#ando set se e9ec#ta con armetros6 lo 7#e hace es asignarlos a las variables $0, $1, $26 etc-tera. Por e9em lo6 a veces s#ele ser reciso determinar la hora act#al a artir del comando date. )l roblema es 7#e este comando m#estra en s# salida estndar #na cadena 7#e informa no s$lo de la hora act#al sino tambi-n del da de la semana6 el mes6 el a<o etc-tera.
$ date lun sep 12 13:08:54 CEST 2005

Para obtener s$lo la hora odramos e9ec#tar el sig#iente comando%


$ set date $ echo $4

/l e9ec#tar date entre tildes graves6 s# salida se convierte en los armetros del comando set6 or lo 7#e el comando anterior es e7#ivalente a teclear%
$ set lun sep 12 13:11:06 CEST 2005

3na ve8 se ha e9ec#tado6 las variables $0, $16 F reciben los valores lun, sep6 F Por lo tanto $4 contendr #na cadena 7#e re resenta la hora act#al.

8.3 Expresiones aritmticas


Bash shell ofrece a los #s#arios la osibilidad de reali8ar o eraciones aritm-ticas sencillas mediante el #so del comando let. )ste comando a licado sobre #na e* resi$n aritm-tica dev#elve como c$digo de retorno el res#ltado de eval#arla. )n la e* resi$n se #eden #sar los o eradores 7#e se recogen en la sig#iente tabla6 agr# ados en orden descendente de rioridad% Operador ! * / % + Significado Genos #nario Negaci$n l$gica G#lti licaci$n6 divisi$n y resto &#ma y resta

15

<= >= < > == != = && ||

A eradores relacionales 4g#aldad y desig#aldad /signaci$n a variable H l$gico A l$gico

"odos estos o eradores6 e*ce to el de asignaci$n6 son asociativos or la i87#ierda. >as e* resiones #eden #sar ar-ntesis ara modificar el orden de eval#aci$n6 ero en ning:n momento se com r#eba si alg#na de ellas rod#ce desbordamiento. / contin#aci$n se m#estran varios e9em los ?B9ese en 7#e no hay ning:n es acio en blanco alrededor del signo =6 ni tam oco alrededor de los o eradores@%
$ let x=2+3 $ echo $x 5 $ let y=x*5 $ echo $y 25

)l :nico #nto de inter-s es 7#e dentro de las e* resiones del comando let las variables6 ese a 7#e se est cons#ltando s# valor6 no es necesario receder s# nombre del signo $. )n c#al7#ier caso6 odemos hacerlo si as lo deseamos6 como se m#estra a contin#aci$n%
$ let x=2+3 $ echo $x 5 $ let y=$x*5 $ echo $y 25

Ieneralmente no e*iste ning:n roblema con la mayora de las e* resiones6 salvo en a7#ellas en las 7#e a arecen los o eradores *6 < o >6 #esto 7#e estos caracteres6 como ya sabemos6 tienen #n significado es ecial ara el shell. Para evitar 7#e el shell los inter rete de #na forma es ecial6 lo me9or es escribir la e* resi$n entre comillas o bien #sar la notaci$n
(( expresin ))

7#e es casi e7#ivalente a escribir


let " expresin "

>a :nica diferencia es 7#e al #sar los dobles ar-ntesis se ermite #sar es acios en blanco alrededor de todos los o erandos y o eradores. 1!

$ (( x = 2 + 3 )) $ echo $x 5 $ (( y = $x * 5 )) $ echo $y 25

8.4 El comando test


)l comando test nos ermite llevar a cabo o eraciones l$gicas sencillas con ficheros6 cadenas y n:meros enteros. )l formato de este comando es
test expresion

A de forma e7#ivalente
[ expresion ]

>a e* resi$n #ede tener c#al7#iera de los formatos 7#e se m#estran en la sig#iente tabla% Patrn -d f -f f -h f -n c -r f -w f -x f -z c c1 = c2 c1 != c2 e1 -eq e2 Significado Cierto si f e*iste y es #n directorio Cierto si f e*iste y no es #n directorio Cierto si f e*iste y es #n enlace simb$lico Cierto si la cadena c no est vaca Cierto si se tiene ermiso de lect#ra en el fichero f Cierto si se tiene ermiso de escrit#ra en el fichero f Cierto si se tiene ermiso de e9ec#ci$n en el fichero f Cierto si la cadena c est vaca Cierto si las dos cadenas son ig#ales Cierto si las dos cadenas son diferentes Cierto si los dos enteros son ig#ales

1'

e1 -ne e2 e1 -gt e2 e1 -ge e2 e1 -lt e2 e1 -le e2 ! e e1 -a e2 e1 -o e2 \( e \)

Cierto si los dos enteros son diferentes Cierto si e1 es mayor estricto 7#e e2 Cierto si e1 es mayor o ig#al 7#e e2 Cierto si e1 es menor estricto 7#e e2 Cierto si e1 es menor o ig#al 7#e e2 Cierto si la e* resi$n e es falsa Cierto si las dos e* resiones son ciertas Cierto si la rimera o la seg#nda e* resi$n o ambas son ciertas >os ar-ntesis se #san ara agr# ar e* resiones y cambiar el orden de eval#aci$n

9. Rutinas
)l bash shell ermite definir bibliotecas de r#tinas de #tilidad 7#e #eden ser com artidas or m#ltit#d de shell scripts. Para escribir #na r#tina se #tili8a la sig#iente sinta*is%
nombre_rutina () { lista de comandos }

Para llamar a #na r#tina basta con escribir s# nombre seg#ida de los armetros adec#ados6 e*actamente ig#al 7#e si est#vi-semos e9ec#tando c#al7#ier otro comando. )n el sig#iente e9em lo se m#estra #na sencilla r#tina 7#e m#estra #n mensa9e de sal#do. Por conveniencia6 conviene escribir todas las r#tinas en ficheros a los 7#e es reciso dar ermiso de e9ec#ci$n #tili8ando el comando chmod.
$ cat > saludo.bsh #!/bin/bash saludo () { echo Hola $1! } # Principal saludo $LOGNAME saludo amigo $LOGNAME saludo

1(

^D $ chmod ugo+x saludo.bsh

>a r#tina saludo se limita a mostrar en antalla #n mensa9e dando la bienvenida a la ersona c#yo nombre se le asa como rimer armetro. No es necesario declarar la r#tina de #na forma es ecial ara indicar 7#e admite armetros y tam oco se reali8a ning:n ti o de com robaci$n en c#anto al n:mero de armetros reales 7#e se #tili8an en la llamada. Para acceder al armetro iE -simo de #na r#tina se #sa la notaci$n $i6 ero si en la llamada ese armetro no ha sido s#ministrado entonces se s#stit#ye or #na cadena vaca. De esta forma6 si e9ec#tamos el anterior shell script obtendremos la salida 7#e se m#estra a contin#aci$n%
$ saludo.bsh Hola juan! Hola amigo! Hola !

B9ese en 7#e en la seg#nda llamada hemos #sado dos armetros y en la tercera ning#no. )n el rimer caso el armetro e*tra es ignorado y en el seg#ndo es s#stit#ido or #na cadena vaca.

9.1Algo ms sobre parmetros


Desgraciadamente6 el mecanismo de variables $i tan s$lo nos ermite acceder a los n#eve rimeros armetros 7#e se le asen a la r#tina. &i es reciso #sar ms armetros dentro de #na r#tina tenemos 7#e rec#rrir al comando shift. Cada ve8 7#e se e9ec#ta des la8a los armetros 7#e se han asado a #na r#tina #na osici$n a la i87#ierda6 de forma 7#e el rimero se ierde6 el seg#ndo se convierte en el rimero y as s#cesivamente. )l sig#iente e9em lo m#estra la forma en 7#e f#nciona este comando%
$ cat > shift.bsh #!/bin/bash desplaza () { echo $1 $2 $3 shift echo $1 $2 $3 shift echo $1 $2 $3 shift } # Programa principal desplaza a b c ^D

1+

$ $ a b c

chmod ugo+x shift.bsh shift.bsh b c c

Para acceder a la lista com leta de armetros odemos #sar la variable es ecial $*6 7#e se e7#ivale a #na cadena con todos los armetros 7#e se han asado a la r#tina se arados or es acios en blanco. Para terminar este est#dio 7#e estamos reali8ando de los armetros6 r#ebe el sig#iente shell script%
$ cat > curioso.bsh #!/bin/bash mas_curioso () { echo curioso ha recibido $# parmetros } curioso () { echo curioso ha recibido $# parmetros mas_curioso $* } # Programa principal curioso "hola $LOGNAME" ^D $ chmod ugo+x curioso.bsh

&i lo e9ec#ta ver 7#e la salida es la sig#iente%


$ curioso.bsh curioso ha recibido 1 parmetros mas_curioso ha recibido 2 parmetros

JC$mo es osible 7#e si a la r#tina curioso se le asa #n armetro y lo #tili8a ara llamar a mas_curioso6 esta r#tina reciba dosK >a ra8$n es 7#e el armetro 7#e se le ha asado a curioso es #na cadena con #n es acio en blanco y el comando
mas_curioso $*

se e* ande como
mas_curioso hola juan

/l no haber comillas alrededor del armetro en esta llamada6 el shell inter reta 20

7#e mas_curioso debe recibir dos armetros% #no con la cadena hola y otro con la cadena juan. )ncerrar la variable $* entre comillas tam oco sirve de m#cho6 ya 7#e en este caso si asamos ms de #n armetro a la r#tina c#rioso6 entonces mas_curioso s$lo recibir #no. )l roblema de los es acios es 7#i8 #no de los ms im ortantes c#ando traba9amos con shell scripts6 #esto 7#e s#elen ser #na f#ente im ortante de errores. Desgraciadamente no e*iste ning#na sol#ci$n sim le.

9.2Valor de retorno
>as r#tinas escritas en bash shell 9 #eden devolver valores de retorno enteros mediante el #so del comando return. Pese a 7#e este comando se #ede #tili8ar en c#al7#ier #nto de la r#tina6 rovocando s# terminaci$n inmediata6 lo ms adec#ado es #sarlo siem re al final. Para determinar c#l es el valor de retorno de c#al7#ier r#tina se #ede #sar la variable es ecial $?. / contin#aci$n se m#estra #n e9em lo de #na r#tina 7#e calc#la y dev#elve la s#ma de los dos n:meros 7#e se le asan.
$ cat > suma.bsh #!/bin/bash suma () { (( result = $1 + $2 )) return $result } # Programa principal suma 1 2 echo "1 + 2 = $?" ^D $ chmod ugo+x suma.bsh $ suma.bsh 1 + 2 = 3

>a variable $? dev#elve realmente el c$digo de salida del :ltimo comando e9ec#tado6 y #na llamada a r#tina no es ms 7#e #n caso artic#lar de e9ec#ci$n de #n comando. )sto significa 7#e si deseamos #tili8ar en varias ocasiones el valor de retorno de #na r#tina6 necesariamente deberemos g#ardarlo en #na variable a#*iliar. Por e9em lo6 el sig#iente c$digo
$ cat > suma.bsh suma 1 2 echo "1 + 2 = $?" echo "2 + 1 = $?"

21

rod#ce al e9ec#tarse la salida sig#iente%


$ suma.bsh 1 + 2 = 3 2 + 1 = 0

>a ra8$n es 7#e c#ando se #sa $? or rimera ve8 dev#elve el res#ltado de haber e9ec#tado la llamada s#ma 1 2. )n cambio c#ando se #sa or seg#nda ve8 dev#elve el c$digo de salida del comando anterior6 esto es6 de echo "1 + 2 = $?". Como este comando se ha e9ec#tado con -*ito6 la seg#nda ve8 7#e se cons#lta la variable $? dev#elve el c$digo de error 0 indicativo de 7#e el :ltimo comando se e9ec#t$ adec#adamente. Gediante el comando return tan s$lo es osible devolver valores enteros. &i deseamos devolver te*to entonces tenemos 7#e #sar el comando echo ara escribirlo en la salida estndar de la f#nci$n y reali8ar #na s#stit#ci$n de comando ara ca t#rar s# salida. / contin#aci$n mostramos #n e9em lo en el 7#e la r#tina saludo dev#elve #n mensa9e sal#dando al #s#ario 7#e la e9ec#ta.
saludo () { echo "Hola $LOGNAME." echo date } msg=saludo echo $msg

9.3Variables locales
Dentro de #na r#tina todas las variables 7#e se definan son globales or defecto6 esto es6 son visibles no s$lo dentro del mbito de la r#tina sino de todo el shell script en el 7#e a arecen. Para introd#cir #na variable de mbito local se #tili8a el comando typeset seg#ido del nombre de la variable. C#ando la definamos osteriormente tan s$lo ser conocida dentro de la r#tina en 7#e ha sido declarada. )n el sig#iente e9em lo se il#stra el #so de este comando.
$ cat > typeset.bsh #!/bin/bash locales () { typeset x (( x = $1 + $2 )) echo local: x = $x return $x }

22

# programa principal x=$LOGNAME echo global: x = $x locales 1 2 echo global: x = $x ^D $ chmod ugo+x typeset.bsh $ typeset.bsh global: x = juan local: x = 3 global: x = juan

9.4Biblioteca de rutinas
)n m#chas ocasiones las r#tinas 7#e escribimos ara #n rograma odran #sarse en otros m#chos. )l bash shell nos ro orciona #n sencillo mecanismo ara agr# ar r#tinas en forma de bibliotecas. Para constr#ir #na biblioteca tan s$lo tiene 7#e teclear las r#tinas 7#e la com onen en #n fichero6 generalmente con la e*tensi$n .bsh6 7#e debe encontrarse en alg#no de los directorios 7#e indica la variable $PATH. Para cargar la biblioteca y oder hacer #so de s#s r#tinas debemos #sar #n comando es ecial llamado =.=. No6 no crea 7#e es #na errata. )l nombre del comando es #n #nto. Por e9em lo%
$ . saludo.bash Hola pepe! Hola amigo! Hola ! $ saludo Juan Hola Juan! $ _

"odos los comandos 7#e no a are8can dentro de #na r#tina en #na biblioteca se e9ec#tan al cargarla. De ah 7#e en el e9em lo anterior a areciesen los tres sal#dos iniciales. / artir de ahora6 en todos los e9ercicios #saremos #na biblioteca m#y :til 7#e nos ermitir mostrar mensa9es de aviso o de error. Gostramos s# c$digo a contin#aci$n%
#!/bin/bsh # error.bash error () { echo "$*" 1>&2 exit 1 } warning ()

23

{ echo "$*" 1>&2 }

10.Sentencias de control
)l bash shell so orta #n con9#nto am lio de sentencias de control estr#ct#rado 7#e nos ermiten tomar decisiones o re etir ciertos gr# os de comandos con facilidad. )n esta secci$n s# ondremos 7#e el lector est familiari8ado con las sentencias de control de alg:n otro leng#a9e de rogramaci$n6 or lo 7#e la descri ci$n 7#e vamos a reali8ar de las mismas ser bastante somera.

10.1case ... in ... esac


>a sinta*is de esta sentencia de control es la sig#iente%
case p1,1 | p1,1 | pm,1 | esac e in p1,2 | | p1,n1 ) lista de comandos ;; p1,2 | | p1,n2 ) lista de comandos ;; pm,2 | | pm,n1 ) lista de comandos ;;

)sta sentencia intenta enca9ar e en alg#no de los atrones pi,j y e9ec#ta la lista de comandos asociada al rimer atr$n en 7#e enca9e. / contin#aci$n se m#estra #n e9em lo en el 7#e se desarrolla #n sencillo rograma 7#e m#estra al #s#ario el calendario del mes 7#e -l mismo decida. )l rograma ace ta #n armetro en el 7#e el #s#ario indica el mes 7#e 7#iere ver ya sea en formato n#m-rico o #sando las tres rimeras letras del nombre del mes en c#al7#ier combinaci$n de may:sc#las o min:sc#las. &i el mes seleccionado no es correcto se m#estra #n mensa9e de error en la antalla.
$ cat > calendario.bsh #!/bin/bash mes=$1 case $mes in [1-9]|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 ;;

24

esac set `date` cal $mes $7 ^D

)n este rograma hemos #sado el comando set date` ara obtener el a<o act#al.

10.2 if ... then ... fi


)ste comando ermite bif#rcar la e9ec#ci$n de #n shell script en f#nci$n a #n con9#nto de e* resiones condicionales. &# sinta*is es la sig#iente%
if l1 then l2 elif l3 then l4 elif l5 then l6 else ln fi

)l comando if e9ec#ta inicialmente la lista de comandos l1. &i el :ltimo comando de esta lista tiene -*ito ?dev#elve el c$digo 0@6 entonces se e9ec#ta la lista de comandos l2. &i el :ltimo comando falla se re ite el mismo es7#ema con cada #na de las ramas elif. &i no se e9ec#ta con -*ito la sentencia asociada a ning#na de ellas entonces se e9ec#ta la lista de sentencias asociada a la rama else. "anto las ramas elif como la rama else son o cionales. / contin#aci$n se m#estra #n sencillo e9em lo 7#e il#stra el comando if.
$ cat > if.bsh #!/bin/bash echo "Teclee un nmero: " 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

25

Teclee un nmero: 12 12 es positivo $ if.bsh Teclee un nmero -1 -1 es negativo

)n este e9em lo hemos hecho #so or rimera ve8 del comando read 7#e 9#ega #n a el com lementario a echo6 #es sirve ara leer datos desde el terminal.

10.3 for ... do ... done


>os b#cles for ermiten e9ec#tar #na lista de comandos en varias ocasiones ba9o el control de #na variable 7#e toma en cada iteraci$n #n valor diferente. / contin#aci$n mostramos la sinta*is%
for v in c1 c2 cn do lista de sentencias done

)l comando for e9ec#ta la lista de sentencias 7#e se le indica asignando en cada v#elta #no de los valores c1 c2 cn a la variable de control v. Para es ecificar los valores 7#e toma la variable de control se #eden #sar atrones arbitrarios 7#e se s#stit#irn or los nombres de los ficheros 7#e enca9en en los mismos. )n el e9em lo 7#e se m#estra a contin#aci$n se desarrolla #n e7#e<o rograma 7#e m#estra los nombre de todos los ficheros de c$digo C 7#e residen en el directorio act#al y en el /tmp.
$ cat > for.bsh #!/bin/bash for f in "Los ficheros de cdigo C son: " *.c /tmp/*.c do echo $f done ^D $ chmod ugo+x for.bsh

10.4 while ... done


>a sinta*is de este comando es la sig#iente%
while l1 do l2

2!

done

while e9ec#ta inicialmente la lista de comandos l1 y finali8a si el :ltimo comando en ella falla. )n otro caso e9ec#ta la lista de comandos l2 y a contin#aci$n re ite el mismo es7#ema #na y otra ve8. )n el sig#iente e9em lo se desarrolla #n rograma 7#e solicita al #s#ario #n n:mero hasta 7#e este est entre 1 y 10.
num=0 while (( num < 1 || num > 10 )) do read num done

10.5 until ... done


>a sinta*is de este comando es la sig#iente%
until l1 do l2 done

#ntil e9ec#ta inicialmente la lista de comandos l1 y finali8a si el :ltimo comando en ella tiene -*ito. )n otro caso e9ec#ta la lista de comandos l2 y a contin#aci$n re ite el mismo es7#ema #na y otra ve8. )n el sig#iente e9em lo se desarrolla #n rograma 7#e solicita al #s#ario #n n:mero hasta 7#e este est entre 1 y 10.
num=0 until (( num >= 1 && num <= 10 )) do read num done

2'

También podría gustarte