Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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.
)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
>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
)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.
*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.
$ # 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
>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
)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
'
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
)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
"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
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.
${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#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.
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
/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.
15
"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 ))
>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
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'
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(
>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.
1+
$ $ a b 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
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
>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
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.
)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
)n este rograma hemos #sado el comando set date` ara obtener el a<o act#al.
)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
)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.
)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
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
#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'