You are here:
Wiki-SL
>
TWikiBar Web
>
TWikiBarConversa003
(03 Feb 2008,
JulioNeves
)
(raw view)
E
dit
A
ttach
---+!! Conversación de Bar Parte III<!--pula duas linhas--> %TOC% - Mozo, traiga dos "choppes" por favor, que hoy voy a tener que hablar mucho. ---++ Trabajando con cadenas Por el título de arriba no pienses que te voy a enseñar a ser carcelero! Me estoy refiriendo a cadenas de caracteres! ---+++ El Comando cut (que no es la central única de trabajadores) <!--pula duas linhas--> Primero te quiero mostrar, de forma eminentemente práctica, una instrucción simple de usar y muy útil: el comando =cut=, Esta instrucción es usada para cortar un determinado pedazo de un archivo y tiene dos formas distintas de uso: ---++++ El comando =cut= con la opción -c Con esta opción, el comando tiene la siguiente sintáxis:%BR% <noautolink> =cut -c PosIni-PosFin [archivo]= </noautolink> Donde:%BR% <noautolink> =PosIni = Posición inicial= %BR% =PosFin = Posición final= </noautolink> %TERMINAL_INI% $ cat números %OUT_INI%1234567890 0987654321 1234554321 9876556789%OUT_FIM% $ cut -c1-5 números %OUT_INI%12345 09876 12345 98765%OUT_FIM% $ cut -c-6 números%OUT_INI% 123456 098765 123455 987655%OUT_FIM% $ cut -c4- números%OUT_INI% 4567890 7654321 4554321 6556789%OUT_FIM% $ cut -c1,3,5,7,9 números%OUT_INI% 13579 08642 13542 97568%OUT_FIM% $ cut -c-3,5,8- números%OUT_INI% 1235890 0986321 1235321 9875789%OUT_FIM% %TERMINAL_FIM% Como se puede ver, en realidad existen cuatro sintaxis distintas: en la primera =(-c1-5)=, especifiqué una franja de posiciones, en la segunda =(-c-6)=, especifiqué todas las posiciones hasta una determinada columna, en la tercera =(-c4-)= de una determinada posición en adelante y en la cuarta =(-c1,3,5,7,9)=, determinadas posiciones. La última =(-c-3,5,8-)= fue solo para demostrar que lo podemos mezclar todo. ---++++ El comando =cut= con la opción -f Pero no pienses que acabó por ahí! Como debes haber notado, esta forma de =cut= es útil para archivos con campos de tamaño fijo, sin embargo, actualmente lo que más existe son archivos con campos de tamaño variables, donde cada campo termina con un delimitador. Vamos a dar una ojeada al archivo =musicas= que comenzamos a preparar en nuestra conversación de la última vez que estuvimos aquí, en el bar. %TERMINAL_INI% $ cat musicas%OUT_INI% album 1^Artista1~Musica1:Artista2~Musica2 album 2^Artista3~Musica3:Artista4~Musica4 album 3^Artista5~Musica5:Artista6~Musica5 album 4^Artista7~Musica7:Artista8~Musica8%OUT_FIM% %TERMINAL_FIM% Entonces, recapitulando, su _"layout"_ es el siguiente:%BR% =nombre del album^intérprete1~nombre de la música1:...:intérpreten~nombre de la músican= O sea, el nombre del álbum será separado por un circunflejo (=^=) del resto del registro, que está formado por diversos grupos, compuestos por el intérprete de cada música del CD y la respectiva música interpretada. Estos grupos son separados entre sí por dos puntos (=:=) e internamente, el nombre del intérprete será separado por una tilde (=~=), del nombre de la música. Entonces para sacar los datos referentes a todas las segundas músicas del archivo =musicas=, debemos hacer: %TERMINAL_INI% $ cut -f2 -d: musicas%OUT_INI% Artista2~Musica2 Artista4~Musica4 Artista6~Musica5 Artista8~Musica8%OUT_FIM% %TERMINAL_FIM% O sea, cortamos el segundo campo (=-f= de _field_ en inglés), delimitado (=-d=) por dos puntos (=:=). En cambio, se quisiéramos solamente los intérpretes, podriamos hacer: %TERMINAL_INI% $ cut -f2 -d: musicas | cut -f1 -d~%OUT_INI% Artista2 Artista4 Artista6 Artista8%OUT_FIM% %TERMINAL_FIM% Para entender esto, vamos a sacar la primera línea de =musicas=: %TERMINAL_INI% $ head -1 musicas%OUT_INI% album 1^Artista1~Musica1:Artista2~Musica2%OUT_FIM% %TERMINAL_FIM% Ahora observa lo que ocurrió: Delimitador del primer =cut= (=:=) =%T1%album 1^Artista1~Musica1%T0%:%T2%Artista2~Musica2%T0%= De esta forma, en el primer =cut=, el primer campo del delimitador (=-d=) dos puntos (=:=), es %T1%album 1^Artista1~Musica1%T0% y el segundo, que es lo que nos interesa, es %T2%Artista2~Musica2%T0%. Vamos ahora a ver lo que pasó con el segundo =cut=: Nuevo delimitador (=~=) =%T1%Artista2%T0%~%T2%Musica2%T0%= Ahora, el primer campo del delimitador (=-d=) tilde (=~=), que es el que nos interesa, es %T1%Artista2%T0% y el segundo es %T2%Musica2%T0%. Si el razonamiento que hicimos para la primera línea fuera aplicado al resto del archivo, llegaríamos a la respuesta anteriormente dada. ---+++ Si hay cut hay paste Como ya era de esperar, el comando =paste= sirve para pegar, sólo que aquí en _Shell_ lo que pega son archivos. Para empezar a entenderlo, vamos a hacer esto:: <verbatim> paste arch1 arch2 </verbatim> De esta forma el comando mandará hacia la salida patrón (=stdout=) cada uno de los registros de =arch1=, al lado de los registros de =arch2= correspondientes y en caso de que no se especifique ningún delimitador, usará por _default_ el =<TAB>=. El paste es un comando poco usado por que su sintaxis es poco conocida. Vamos a jugar con 2 archivos creados de la siguiente forma: %TERMINAL_INI% $ seq 10 > enteros $ seq 2 2 10 > pares %TERMINAL_FIM% Para ver el contenido de los archivos creados, vamos a usar el =paste= en su forma simple que mostramos arriba: %TERMINAL_INI% $ paste enteros pares%OUT_INI% 1 2 2 4 3 6 4 8 5 10 6 7 8 9 10%OUT_FIM% %TERMINAL_FIM% ---++++ Quién está de pié, se acuesta. Ahora vamos a transformar la columna del =pares= en línea: %TERMINAL_INI% $ paste -s pares%OUT_INI% 2 4 6 8 10%OUT_FIM% %TERMINAL_FIM% ---++++ Usando separadores Como ya fue dicho, el separador _default_ del =paste= es el =<TAB>=, pero eso puede ser alterado con la opción =-d=. Entonces para calcular la suma del contenido de =pares= primeramente haríamos: %TERMINAL_INI% $ paste -s -d'+' pares # también podría ser -sd'+'%OUT_INI% 2+4+6+8+10%OUT_FIM% %TERMINAL_FIM% y después pasaríamos esta línea con _pipe_ (=|=) hacia la calculadora (=bc=), y entonces quedaría: %TERMINAL_INI% $ paste -sd'+' pares | bc%OUT_INI% 30%OUT_FIM% %TERMINAL_FIM% De esta forma, para calcular el factorial del número contenido en =$Num=, basta hacer: %TERMINAL_INI% $ seq $Num | paste -sd'*' | bc %TERMINAL_FIM% Con el comando =paste= tu también puedes montar formatos exóticos como el siguiente: %TERMINAL_INI% $ ls | paste -s -d'\t\t\n'%OUT_INI% arch1 arch2 arch3 arch4 arch5 arch6%OUT_FIM% %TERMINAL_FIM% Lo que pasó fue lo siguiente: se le especifico al comando =paste= que tendría que transformar líneas en columnas (por la opción =-s=) y que sus separadores (si...! acepta más de uno, pero solamente uno después de cada columna creada por el comando) serían un =<TAB>=, otro =<TAB>= y un =<ENTER>=, generando de esta forma su salida tabulada en 3 columnas. Ahora que ya entendiste esto, observa como hacer lo mismo, pero de forma más fácil, menos extraño y primitivo, usaremos el mismo comando pero con la siguiente sintaxis: %TERMINAL_INI% $ ls | paste - - -%OUT_INI% arch1 arch2 arch3 arch4 arch5 arch6%OUT_FIM% %TERMINAL_FIM% Y esto sucede porque si en lugar de especificar los archivos, colocamos el signo de menos (=-=), el comando =paste= los substituye por la salida o entrada patrón conforme al caso. En el ejemplo anterior los datos fueran mandados hacia la salida patrón (=stdout=), porque el _pipe_ (=|=) estaba desviando la salida del =ls= hacia la entrada patrón (=stdin=) del =paste=, pero veamos el ejemplo siguiente: %TERMINAL_INI% $ cat arch1%OUT_INI% predisposición privilegiado profesional%OUT_FIM% $ cat arch2%OUT_INI% ver mario motor%OUT_FIM% $ cut -c-3 arq1 | paste -d "" - arq2%OUT_INI% prever primario promotor%OUT_FIM% %TERMINAL_FIM% En este caso, el =cut= devolvió las tres primeras letras de cada registro de =arch1=, el =paste= fue montado para no tener separador (=-d""=) y recibir la entrada patrón (desviada por el _pipe_) en el trazo (=-=), generando la salida junto con =arch2=. ---+++ El Comando tr Otro comando muy interesante es el =tr= que sirve para substituir, comprimir o retirar caracteres. Su sintaxis sigue el siguiente patrón: <verbatim> tr [opciones] cadena1 [cadena2] </verbatim> El comando =tr= copia el texto de la entrada patrón (_stdin_) y cambia, las veces que encuentre, los caracteres de =cadena1= por el correspondiente contenido de la =cadena2=, o cambia las múltiples coincidencias de los caracteres de =cadena1= por solamente un carácter, o todavía puede hacer mas, puede eliminar los caracteres de la =cadena1=. Las principales =opciones= del comando son: <center> %TABLE{ databg="#ffffff" headerrows="1" }% | *Principales Opciones del comando tr* || | *Opción* | *Significado* | | -s | Comprime n coincidencias de la cadena1 en sólo una | | -d | Elimina del archivo los caracteres de la cadena1 | </center> ---++++ Cambiando caracteres con =tr= Primero te voy a dar un ejemplo bien bobo: %TERMINAL_INI% $ echo bobo | tr o a%OUT_INI% baba%OUT_FIM% %TERMINAL_FIM% O sea, cambié todas las coincidencias de la letra =o= por la letra =a=. Suponte que en un determinado punto de mi _script_, pido al operador que teclee =s= o =n= (si o no), y guardo su respuesta en la variable =$Resp=. El contenido de =$Resp= puede estar con letras mayúsculas o minúsculas, y de esta forma tendría que hacer diversos tests para saber si la respuesta dada fue =S=, =s=, =N= o =n=. Entonces lo mejor es hacer: %TERMINAL_INI% $ Resp=$(echo $Resp | tr SN sn) %TERMINAL_FIM% y despues de ejecutar este comando tendría la seguridad de que el contenido de =$Resp= seria un =s= o un =n=. Si mi archivo =ArchEnt= está todo escrito con letras mayúsculas y deseo pasarlas para minúsculas hago: <noautolink> %TERMINAL_INI% $ tr A-Z a-z < ArchEnt > /tmp/$$ $ mv -f /tmp/$$ ArchEnt %TERMINAL_FIM% </noautolink> Observa que en este caso usé la notación =A-Z= para no tener que escribir =ABCD...YZ=. Otro tipo de notación que puede ser usada son las _escape sequences_ (preferiría escribir en español, pero en este caso como lo traduciría? Secuencias de escape? Medio sin sentido, no te parece? Pero continuemos...) que también son reconocidas por otros comandos y también en lenguaje C, y cuyo significado verás a continuación: <center> %TABLE{ databg="#ffffff" headerrows="1" }% | *Escape Sequences* ||| | *Secuencia* | *Significado* | *Octal* | | \t | Tabulación | \011 | | \n | Nueva línea <ENTER> | \012 | | \v | Tabulación Vertical | \013 | | \f | Nueva Página | \014 | | \r | Início de línea <^M> | \015 | | \\ | Una barra invertida | \0134 | </center> ---++++ Sacando caracteres con =tr= Dejame contarte un "causo": un alumno que estaba enojado conmigo, decidió complicarme la vida y en un ejercicio práctico que pasé para ser hecho en el computador, y que valía para nota, me entregó el _script_ con todos los comandos separados por punto y coma (recuerdas que te dije que el punto y coma servía para separar diversos comandos en una misma línea?). Te voy a dar un ejemplo simplificado e idiota de un "chorizo" así: %TERMINAL_INI% $ cat confuso%OUT_INI% echo lea Programación Shell Linux de Julio Cezar Neves > libro;cat libro;pwd;ls;rm -f lixo 2>/dev/null;cd ~%OUT_FIM% %TERMINAL_FIM% Yo ejecutaba el programa y se ejecutaba así: %TERMINAL_INI% $ confuso%OUT_INI% lea Programación Shell Linux de Julio Cezar Neves /home/jneves/LM confuso livro musexc musicas musinc muslist numeros%OUT_FIM% %TERMINAL_FIM% Pero nota de prueba es cosa seria (y billete de dólar todavia más :) ) entonces, para entender lo que el alumno habia hecho, lo llamé y delante suyo ejecuté el siguiente comando: %TERMINAL_INI% $ tr ";" "\n" < confuso%OUT_INI% echo lea Programación Shell Linux de Julio Cezar Neves pwd ls rm -f lixo 2>/dev/null%OUT_FIM% cd ~ %TERMINAL_FIM% El alumno se quedó muy triste, porque en 2 o 3 segundos le deshice la broma en la había perdido varias horas.%BR% Ahora fíjate bien! Si yo tuviera una máquina con Unix, habria hecho lo siguiente: %TERMINAL_INI% $ tr ";" "\012" < confuso %TERMINAL_FIM% ---++++ X(com)primiendo con =tr= Observa ahora la diferencia entre los dos comandos =date=: el que hice hoy y el otro que fue ejecutado hace dos semanas: %TERMINAL_INI% $ date # Hoy%OUT_INI% Sun Sep 19 14:59:54 2006%OUT_FIM% $ date # Hace dos semanas%OUT_INI% Sun Sep 5 10:12:33 2006%OUT_FIM% %TERMINAL_FIM% Para ver la hora debería hacer: %TERMINAL_INI% $ date | cut -f 4 -d ' '%OUT_INI% 14:59:54%OUT_FIM% %TERMINAL_FIM% Sin embargo, dos semanas antes ocurriría lo siguiente: %TERMINAL_INI% $ date | cut -f 4 -d ' '%OUT_INI% 5%OUT_FIM% %TERMINAL_FIM% Ahora observa porqué: %TERMINAL_INI% $ date # Hace dos semanas%OUT_INI% Sun Sep 5 10:12:33 2004%OUT_FIM% %TERMINAL_FIM% Como puedes notar, existen 2 caracteres en blanco antes del =5= (día), esto lo confunde todo porque el tercer pedazo está vacio y el cuarto es el día (=5=). Entonces lo ideal sería comprimir los espacios en blanco sucesivos en solamente un espacio, para poder tratar las dos cadenas resultantes del comando =date= de la misma forma, y eso se hace así: %TERMINAL_INI% $ date | tr -s " "a%OUT_INI% Sun Sep 5 10:12:33 2004%OUT_FIM% %TERMINAL_FIM% Como puedes ver, no existen los dos espacios, Entonces ahora podria cortar: %TERMINAL_INI% $ date | tr -s " " | cut -f 4 -d " "%OUT_INI% 10:12:33%OUT_FIM% %TERMINAL_FIM% Viste como el _Shell_ ya está solucionando problemas! Observa este archivo que fue bajado de una máquina con aquél sistema operativo que sufre de todos los vírus: <noautolink> %TERMINAL_INI% $ cat -ve ArqDoDOS.txt%OUT_INI% Este archivo^M$ fue generado por^M$ DOS/Rwin y fue^M$ bajado por un^M$ ftp mal hecho.^M$%OUT_FIM% %TERMINAL_FIM% </noautolink> y ahora te quiero dar dos consejos: %DICA_INI% *Consejo #1* - La opción =-v= del =cat= muestra los caracteres de control invisibles, con la notación =^L=, donde =^= es la tecla control y =L= es la respectiva letra. La opción =-e= muestra el final de la línea como un signo de pesos (=$=). %DICA_FIM% %DICA_INI% *Consejo #2* - Esto ocurre porque en formato DOS (o rwin), el fin de los registros está formado por un _carriage-return_ (=\r=) y un _line-feed_ (=\n=). En Linux sin embargo, el final del registro tiene solamente el _line-feed_. %DICA_FIM% Vamos entonces a limpiar este archivo. <noautolink> %TERMINAL_INI% $ tr -d '\r' < ArchDeDOS.txt > /tmp/$$ $ mv -f /tmp/$$ ArchDeDOS.txt %TERMINAL_FIM% </noautolink> Ahora vamos a ver lo que pasó: <noautolink> %TERMINAL_INI% $ cat -ve ArchDeDOS.txt%OUT_INI% Este archivo$ fue generado por el$ DOS/Rwin y fue$ bajado por un$ ftp mal hecho.$%OUT_FIM% %TERMINAL_FIM% </noautolink> Bien, la opción =-d= del =tr= retira los caracteres especificados de todo el archivo. De esta forma retiré los caracteres no deseados, grabandolo en un archivo de trabajo temporal y posteriormente lo renombré con su nombre original.%BR% Obs: En Unix debería hacer: <noautolink> %TERMINAL_INI% $ tr -d '\015' < ArchDeDOS.txt > /tmp/$$ %TERMINAL_FIM% </noautolink> %ATENCION_INI% Esto pasó porque el =ftp= fue hecho de modo binario (o =image=), o sea, sin la interpretación del texto. Si antes de la transmisión del archivo hubiera sido estipulada la opción =ascii= del =ftp=, esto no habría ocurrido. %ATENCION_FIM% - Mira, después de este consejo, estoy comenzando a disfrutar de ese tal _Shell_, pero todavia hay muchas cosas que no consigo hacer. - Claro!, si hasta aqui no te hablé casi nada sobre programación en _Shell_, tenemos muchas cosas aun por avanzar, sin embargo, con lo que aprendiste, ya te da para resolver muchos problemas, hasta que tú adquieras el “modo _Shell_ de pensar”. Serías capaz de hacer un _script_ para decirme quienes son las personas que están “logadas” desde hace más de un dia en tu servidor? - Claro que no! Para eso seria necesario que conociera los comandos condicionales que todavia no me explicaste como funcionan. - Dejame intentar cambiar un poco tu lógica y atraerla hacia el “modo _Shell_ de pensar”, pero antes es mejor tomar un chope... Chico!, traeme otros dos... - Ahora que ya moje el gaznate, vamos a resolver el problema que te propuse. Presta atención a como funciona el comando who: %TERMINAL_INI% $ who%OUT_INI% jneves pts/1 Sep 18 13:40 rtorres pts/0 Sep 20 07:01 rlegaria pts/1 Sep 20 08:19 lcarlos pts/3 Sep 20 10:01%OUT_FIM% %TERMINAL_FIM% Y mira también el =date=: %TERMINAL_INI% $ date%OUT_INI% Mon Sep 20 10:47:19 BRT 2004%OUT_FIM% %TERMINAL_FIM% Ves que el mes y el dia están en el mismo formato en ambos comandos? %DICA_INI% Algunas vezes un comando tiene la salida en portugués y el otro en inglés. Cuando eso pase, puedes usar el siguiente artificio: %TERMINAL_INI% $ date%OUT_INI% Mon Sep 20 10:47:19 BRT 2004%OUT_FIM% $ LANG=pt_BR date%OUT_INI% Seg Set 20 10:47:19 BRT 2004%OUT_FIM% %TERMINAL_FIM% Y así pasas la salida del comando =date= hacia portugués, o hacia cualquier otro idioma que quieras. %DICA_FIM% Entonces, si en algún registro del =who= no encuentro la fecha de hoy, significa que el individuo está "logado" hace más de un día, ya que él no puede haberse "logado" mañana... Vamos a guardar el pedazo que importa de la fecha de hoy para buscarla en la salida del =who=: %TERMINAL_INI% $ Fecha=$(date | cut -c 5-10) %TERMINAL_FIM% Aquí usé la construcción =$(...)=, para dar prioridad a la ejecución de los comandos antes de atribuir a su salida a la variable =$Fecha=. Vamos a ver si funcionó: %TERMINAL_INI% $ echo $Fecha%OUT_INI% Sep 20%OUT_FIM% %TERMINAL_FIM% Muy bien! Ahora, lo que tenemos que hacer es buscar con el comando =who= los registros que no poseen esta fecha. - Ah! Me parece que estoy entendiendo! Ahora que mencionaste lo de buscar, se me ocurrió el comando =grep=, acerté? - Correctísimo! Solo que tengo que usar el =grep= con aquella opción que solamente lista los registros en los quales *no* encontró la cadena. Te acuerdas que opción es esa? - Claro, es la opción =-v=... - Eso mismo! Estás quedando un lujo! Entonces vamos a ver: %TERMINAL_INI% $ who | grep -v "$Fecha"%OUT_INI% jneves pts/1 Sep 18 13:40%OUT_FIM% %TERMINAL_FIM% - Y si quisiera un poco mas de adornos,haría así: %TERMINAL_INI% $ who | grep -v "$Fecha" | cut -f1 -d ' '%OUT_INI% jneves%OUT_FIM% %TERMINAL_FIM% - Te diste cuenta? No fue necesario usar ningún comando condicional, porque además nuestro comando condicional más usado, el famoso =if=, no verifica condición sino instrucciones, como veremos ahora. ---++ Comandos Condicionales Observa las líneas de comando que siguen: <noautolink> %TERMINAL_INI% $ ls musicas%OUT_INI% musicas%OUT_FIM% $ echo $?%OUT_INI% 0%OUT_FIM% $ ls ArchInexistente%OUT_INI% ls: ArchInexistente: No such file or directory%OUT_FIM% $ echo $?%OUT_INI% 1%OUT_FIM% $ who | grep jneves%OUT_INI% jneves pts/1 Sep 18 13:40 (10.2.4.144)%OUT_FIM% $ echo $?%OUT_INI% 0%OUT_FIM% $ who | grep juliana%OUT_INI% $ echo $?%OUT_FIM% 1 %TERMINAL_FIM% </noautolink> - y que hace ese =$?= por ahí? Comenzando por pesos (=$=) parece ser una variable, correcto? - Si, es una variable que contiene el código de salida de la última instrucción ejecutada. Te puedo garantizar que si esta instrucción fué bien ejecutada, $? tendrá el valor cero, en caso contrario su valor será diferente de cero. ---+++ El Comando if Lo que nuestro comando condicional =if= hace es testar la variable =$?=. Veamos entonces a ver su sintaxis:%BR% <verbatim> if cmd then cmd1 cmd2 cmdn else cmd3 cmd4 cmdm fi </verbatim> o sea: en caso que el comando =cmd= haya sido ejecutado con éxito, los comandos del bloque del =then= (=cmd1=, =cmd2= y =cmdn=) serán ejecutados, en caso contrario, los comandos ejecutados serán los del bloque opcional del =else= (=cmd3=, =cmd4= y =cmdm=), terminando con un =fi=. Vamos a ver en la prática como funciona eso usando un _scriptisiño_ que sirve para incluir usuários en el =/etc/passwd=: %TERMINAL_INI% $ cat incusu%OUT_INI% #!/bin/bash # Versión 1 if grep ^$1 /etc/passwd then echo Usuario \'$1\' ya existe else if useradd $1 then echo Usuario \'$1\' incluído en /etc/passwd else echo "Problemas en el catastro. Usted es root?" fi fi%OUT_FIM% %TERMINAL_FIM% Nota que el =if= está verificando diretamente el comando =grep= y ésta es su finalidad. En caso de que el =if= sea exitoso, o sea, el usuário (cuyo nombre está en =$1=) fuera encontrado en =/etc/passwd=, los comandos del bloque del =then= serán ejecutados (en este ejemplo es solamente el =echo=) y en el caso contrario, las instrucciones del bloque del =else= son las que serán ejecutadas, entonces un nuevo =if= verifica si el comando =useradd= fué bien ejecutado , creando el registro del usuario en =/etc/passwd=, o no, y es entonces cuando dará el mensaje de error.%BR% Veamos su ejecución, primero pasando un usuario ya existente: %TERMINAL_INI% $ incusu jneves%OUT_INI% jneves:x:54002:1001:Julio Neves:/home/jneves:/bin/bash Usuario 'jneves' ya existe%OUT_FIM% %TERMINAL_FIM% Como ya vimos diversas veces, pero siempre es bueno insistir en el tema para que te quede claro, en el ejemplo anterior surgió una línea no deseada, esta es la salida del comando =grep=. Para evitar que eso pase, debemos desviar la salida de esta instrucción para =/dev/null=, quedando así: %TERMINAL_INI% $ cat incusu%OUT_INI% #!/bin/bash # Versión 2 if grep ^$1 /etc/passwd > /dev/null # o: if grep -q ^$1 /etc/passwd then echo Usuario \'$1\' ya existe else if useradd $1 then echo Usuario \'$1\' incluído en /etc/passwd else echo "Problemas en el catastro. Usted es root?" fi fi%OUT_FIM% %TERMINAL_FIM% Ahora vamos a verificarlo, pero como usuario normal (no _root_): <noautolink> %TERMINAL_INI% $ incusu JuanNadie%OUT_INI% ./incusu[6]: useradd: not found Problemas en el catastro. Usted es root?%OUT_FIM% %TERMINAL_FIM% </noautolink> Epa!, aquél error no tenia que pasar! Para evitar que eso suceda debemos mandar también la salida de error (_strerr_, te acuerdas?) del =useradd= hacia =/dev/null=, quedando la versión final así: %TERMINAL_INI% $ cat incusu%OUT_INI% #!/bin/bash # Versión 3 if grep ^$1 /etc/passwd > /dev/null then echo Usuario \'$1\' ya existe else if useradd $1 2> /dev/null then echo Usuario \'$1\' incluído en /etc/passwd else echo "Problemas en el catastro. Usted es root??" fi fi%OUT_FIM% %TERMINAL_FIM% Después de estas alteraciones y de hacer un =su –= (volverme _root_) veamos su comportamiento: %TERMINAL_INI% $ incusu perez%OUT_INI% Usuario 'perez' incluído en /etc/passwd%OUT_FIM% %TERMINAL_FIM% Y nuevamente: %TERMINAL_INI% $ incusu perez%OUT_INI% Usuario 'perez' ya existe%OUT_FIM% %TERMINAL_FIM% Recuerdas que te dije que a lo largo de nuestras conversaciones y "choppes" nuestros programas irían mejorando? Entonces veamos ahora como podríamos mejorar nuestro programa para incluir músicas: %TERMINAL_INI% $ cat musinc%OUT_INI% #!/bin/bash # Incluye CDs (versión 3) # if grep "^$1$" musicas > /dev/null then echo Este álbum ya está incluído else echo $1 >> musicas sort musicas -o musicas fi%OUT_FIM% %TERMINAL_FIM% Como viste, es una pequeña evolución de la versión anterior, de forma que, antes de incluir un registro (que con la versión anterior podría ser duplicado), verificamos si el registro comenzaba (=^=) y terminaba (=$=) igual al parámetro pasado (=$1=). El uso del circunflejo (=^=) en el inicio de la cadena y el pesos (=$=) en el fin, son para verificar si el parámetro pasado (el álbum y sus datos) son exactamente iguales a algún registro anteriormente incluído y no unicamente igual a un pedazo de alguno de los registros.%BR% Vamos a ejecutarlo pasando un álbum ya anteriormente incluído: %TERMINAL_INI% $ musinc "album 4^Artista7~Musica7:Artista8~Musica8"%OUT_INI% Este álbum ya está incluído%OUT_FIM% %TERMINAL_FIM% Y ahora uno no incluído: %TERMINAL_INI% $ musinc "album 5^Artista9~Musica9:Artista10~Musica10" $ cat musicas%OUT_INI% album 1^Artista1~Musica1:Artista2~Musica2 album 2^Artista3~Musica3:Artista4~Musica4 album 3^Artista5~Musica5:Artista6~Musica5 album 4^Artista7~Musica7:Artista8~Musica8 album 5^Artista9~Musica9:Artista10~Musica10%OUT_FIM% %TERMINAL_FIM% - Como viste, el programa mejoró un poquito, pero todavia no está listo. A medida que te vaya enseñando a programar en _shell_, nuestra CDteca va a ir quedando cada vez mejor. - Entendí todo lo que me explicaste, pero todavia no sé como hacer un =if= para verificar condiciones, o sea el uso normal del comando. - Mira, para eso existe el comando =test=, él es quien verifica condiciones. El comando =if= verifica el comando =test=. Pero eso está medio confuso y como ya hablé mucho, estoy necesitando unos "choppes" para mojar las palabras. Vamos a parar por aqui y la próxima vez te explico claramente el uso del =test= y de diversas otras sintáxis del =if=. - Estamos de acuerdo entonces! Me parece bien porque yo tambiém estoy quedando tonto y así aprovecho para practicar esa cantidad de cosas de las cuales me hablaste hoy . - Para memorizar lo que aprendiste, trata de hacer un _scriptiziño_ para informar si un determinado usuario, que será pasado como parámetro está logado (ajjjhh!) o no. - Chico,dos "choppes" más por favor... Y no te olvides, cualquer duda o falta de compañia para tomar una cerveza o hasta para hablar mal de los políticos lo único que tienes que hacer es mandarme un e-mail para <a href="mailto:julio.neves@gmail.com?Subject=Dudas Conversas de bar botequim">julio.neves@gmail.com</a>. Voy aprovechar tambiém para mandar mi aviso publicitario: puedes decirle a los amigos que quien quiera hacer un curso nota diez de programación en _Shell_ que mande un e-mail para <a href="mailto:julio.neves@uniriotec.br?Subject=Curso de Shell con Julio Neves">julio.neves@uniriotec.br</a> para informarse. Gracias y hasta la <a href="https://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarConversa004">próxima</a> -- Main.HumbertoPina - 04 Oct 2006
E
dit
|
A
ttach
|
P
rint version
|
H
istory
: r7
<
r6
<
r5
<
r4
<
r3
|
B
acklinks
|
V
iew topic
|
M
ore topic actions
Topic revision: r7 - 03 Feb 2008 - 14:08:50 -
JulioNeves
TWikiBar
Página Inicial
Últimas alterações
Índice
Procurar
Estatísticas de Uso
Aviso de Atualização
Configurações Gerais
Projeto Gráfico
Mapa do Site
Quem Somos
Registre-se
?
Regras de Formatação
Biblioteca Gráfica
?
Carinhas Gráficas
Webs Wiki-SL
Amadeu
Anapolivre
ArquivoLivre
Arte
BahiaSocial
BeaBa
BibliotecaLivre
Blogs
BrasilDigital
BrasilELivre
BSM
Ccsa
CESL
CoberturaWiki
Cooperativas
Curriculo
DarvinMarosin
DiaD
Dinamicoop
Economia
EconomiaSolidaria
EducacaoLivre
Ekaaty
Emacsbr
ENSL
Fatos
Festival3
Festival4
Flisol
Fmpb
Formatos
Foswikibr
FSM2005
GNOMEBR
GTTemario2004
GTWeb
Guialivre
HDC
Incubus
InkscapeBrasil
Jogos
KdeBR
KSP
LGM
LinuxStokDoc
Livros
Main
Mentores
MHHOB
MinuanoDigital
MoradiaECidadania
OlhosDagua
Olimpo
OLPC
OOPTQ
Papers
PCLivre
PentahoBrasil
Pessoas
Portal
Prefeituras
PSLAL
PSLBA
PSLBancarios
PSLBrasil
PSLGO
PSLMA
PSLMG
PSLMIP
PSLMT
PSLMulheres
PSLPI
PubFisl10
PubFisl7
PubFisl8
PubFisl9
QuilomboDoSopapo
RadioSL
RedeMesh
RedePopular
RobotWars
Sandbox
Saudelivre
Scribus
Sementes
Shakya
SLRJ
SoftwareLivreIrece
SoftwareLivreVS
SoLiSC
SuporteLivre
System
Telecentros
TeseSA
TextoLivre
TV
TWikiBar
TWikiPtbr
UNELivre
UNIMIX
VilaTorres
WebNordeste
WTRD2004
Este Menu
?skin=free
English
Español
Português brasileiro
Copyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Wiki-SL?
Send feedback