Difference: TWikiBarConversa006 (1 vs. 7)

Revision 725 Dec 2017 - Main.PauloSantana

Line: 1 to 1
 

Conversación de Bar Parte VI

Line: 433 to 433
       - Mozo, trae otro "chopp" mientras él piensa!
Changed:
<
<
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 julio.neves@uniriotec.br para informarse.
>
>
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 julio.neves@gmail.com para informarse.
 
Changed:
<
<
Gracias y hasta la próxima
>
>
Gracias y hasta la próxima
  -- HumbertoPina - 28 Nov 2006
Changed:
<
<
>
>
-- PauloSantana - 25 Dec 2017

Revision 614 Feb 2012 - MarioSilva

Line: 1 to 1
 

Conversación de Bar Parte VI

Line: 438 to 438
 Gracias y hasta la próxima

-- HumbertoPina - 28 Nov 2006

Added:
>
>

Revision 505 Feb 2008 - CollonsTorre

Line: 1 to 1
 

Conversación de Bar Parte VI

Comandos de Loop o Lazo (Continuación)

Changed:
<
<
     - Que tal mi amigo, como anda? Ya está sabiendo todo acerca del comando for? Te dejé un ejercicio de deberes, si no estoy equivocado, era para contar la cantidad de palabras de un archivo... Lo hiciste?
>
>
     - Que tal amigo mio, como estas? Ya lo sabes todo acerca del comando for?. Te dejé un ejercicio de deberes, y si no estoy equivocado, era para contar la cantidad de palabras de un archivo... Lo hiciste?
 
Changed:
<
<
     - Claro! Estoy entusiasmando con ese lenguaje del shell, lo hice de la forma que me pediste, o sea sin usar el comando wc porque si no era mucho más fácil. Mira lo que hicei...
>
>
     - Claro! Estoy entusiasmando con ese lenguaje del shell, lo hice de la forma que me pediste, o sea sin usar el comando wc porque si no era mucho más fácil. Mira lo que hice...
 
Changed:
<
<
     - Epa! Un momento! Realmente estás entusiasmando con el lenguaje, pero yo estoy deseando tomar un chopp. Chico!, traeme dos por favor. Uno sin espuma, como siempre!
>
>
     - Epa! Un momento! Realmente estás entusiasmando con el lenguaje, pero yo estoy deseando tomar un "chopp". Chico!, tráeme dos por favor. Uno sin espuma, como siempre!
 
Changed:
<
<
     - Como te iba diciendo, vé lo que hice. Es muy fácil...
>
>
     - Como te iba diciendo, mira lo que hice. Es muy fácil...
 
$ cat contpal.sh
Line: 34 to 34
 echo El archivo $1 tiene $Cont palabras.
Changed:
<
<
O sea, el programa comienza como siempre verificando si el pasaje de parámetros fue correcto, en seguida el comando for se encarga de agarrar cada una de las palabras (recuerda que el $IFS padrón (default) es espacio, <TAB> y <ENTER>, que es exactamente lo que deseamos para separar las palabras), incrementando la variable $Cont.
>
>
O sea, el programa comienza como siempre verificando si el pasaje de parámetros fue correcto, en seguida el comando for se encarga de coger cada una de las palabras (recuerda que el $IFS patrón (default) es espacio, <TAB> y <ENTER>, que es exactamente lo que deseamos para separar las palabras), incrementando la variable $Cont.
  Vamos a recordar como es el archivo ArchDelDOS.txt.
Line: 47 to 47
 ftp mal hecho.
Changed:
<
<
Ahora vamos a testar el programa pasando este archivo como parámetro:
>
>
Ahora vamos a testear el programa pasando este archivo como parámetro:
 
$ contpal.sh ArchDelDOS.txt
Line: 58 to 58
 

Un Poco más de for y Matemática

Changed:
<
<
Volviendo a nuestro tema, la última vez que estuvimos aqui, terminamos nuestra conversación mostrando el loop de for a seguir:
>
>
Volviendo a nuestro tema, la última vez que estuvimos aquí, terminamos nuestra conversación mostrando el loop del for a continuación:
 
    for ((; i<=9;))
Line: 68 to 68
  done
Changed:
<
<
Una vez que llegamos a este punto, creo que sea bastante interesante citar que el Shell trabaja con el concepto de "Expansión Aritmética" (Arithmetic Expansion) que es accionado por una construcción de la forma
>
>
Una vez que llegamos a este punto, creo que sera bastante interesante citar que el Shell trabaja con el concepto de "Expansión Aritmética" (Arithmetic Expansion) que es accionado por una construcción de la forma
       $((expresión))
Line: 76 to 76
       let expressión
Changed:
<
<
En el último for citado, usé la expansión de las dos formas, pero no poderíamos seguir adelante sin saber que la expresión puede ser una de las listadas a seguir:
>
>
En el último for citado, usé la expansión de las dos formas, pero no podríamos seguir adelante sin saber que la expresión puede ser una de las listadas a continuación:
 
Line: 93 to 93
 
||   O lógico
Changed:
<
<
     - Y piensas que la conversación sobre loop (o lazo) se encierra en el comando for? Craso engaño amigo, vamos a partir de ahora a ver dos más.
>
>
     - Y si piensas que la conversación sobre loop (o lazo) se termina en el comando for, estas en un gran error amigo, vamos a partir de ahora a ver dos más.
 

El comando while

Changed:
<
<
Todos los programadores conocen este comando, ya que es común a todas los lenguajes y en ellos lo que normalmente ocurre, es que un bloque de comandos es ejecutado, en cuanto que (en cuanto que en inglés es while) una determinada condición sea verdadera. Pues bien, esto es lo que ocurre en otros lenguajes! En programación Shell, el bloque de comandos es ejecutado en cuanto que un comando sea verdadero. Y es claro, si quisiera verificar una condición use el comando while junto con el comando test, exactamente como aprendiste a hacer en el if, recuerdas?
>
>
Todos los programadores conocen este comando, ya que es común a todas los lenguajes y en ellos lo que normalmente ocurre, es que un bloque de comandos es ejecutado, en cuanto que (en cuanto que en inglés es while) una determinada condición sea verdadera. Pues bien, esto es lo que ocurre en otros lenguajes! En programación Shell, el bloque de comandos es ejecutado en cuanto que un comando sea verdadero. Y esta claro, si quisiera verificar una condición, usaria el comando while junto con el comando test, exactamente como aprendiste a hacer en el if, recuerdas?
 
Changed:
<
<
Entonces, la sintáxis del comando queda de la siguiente forma:
>
>
Entonces, la sintaxis del comando queda de la siguiente forma:
 
    while comando
Line: 112 to 112
  done
Changed:
<
<
y de esta forma el bloque de comandos formado por las instrucciones cmd1, cmd2,... y cmdn será ejecutado en cuanto que la ejecución de la instrucción comando sea ejecutada con suceso.
>
>
y de esta forma el bloque de comandos formado por las instrucciones cmd1, cmd2,... y cmdn será ejecutado en cuanto que la ejecución de la instrucción comando sea ejecutada con éxito.
 
Changed:
<
<
Suponga la seguinte escena: tengo una tremenda gata esperandome y estoy preso en el trabajo in poder salir porque mi jefe, que es un tremendo rompre cocos se encuentra todavia trabajando en su escritorio, que queda bien en medio de mi salida a la calle.
>
>
Suponga la siguiente escena: tengo una tremenda gatita esperándome y estoy preso en el trabajo sin poder salir porque mi jefe, que es un tremendo rompe cocos se encuentra todavía trabajando en su escritorio, que queda bien en medio de mi salida a la calle.
 
Changed:
<
<
Él comenzó a quedar con las antenas (probablemente instaladas en su cabeza por la esposa) atentas, después de la quinta vez que me vió pasar por su puerta y ver que todavia estaba alli. Volví a mi mesa e hice un script en el servidor de esta forma:
>
>
Él empezó a tener las antenas (probablemente instaladas en su cabeza por la esposa) atentas, después de la quinta vez que me vio pasar por su puerta y ver que todavía estaba allí. Volví a mi mesa e hice un script en el servidor de esta forma:
 
$ cat logaute.sh
Line: 126 to 126
 do sleep 30 done
Changed:
<
<
echo El rompe se fue, no hesite, dé un exit y va enfrente
>
>
echo El rompe se fue, no te entretengas, date el piro y ves enfrente
 
Changed:
<
<
En este scriptiziño, el comando while verifica el pipeline compuesto por el who y por el grep y que será verdadero en cuanto el grep localize la palabra jefe en la salida del who. Así, el script dormirá por 30 segundos en cuanto el jefe esté logado (Argh!). Cuando él se desconecte del servidor, el flujo del script salirá del loop y dará el tan ansiado mensaje de libertad.
>
>
En este scriptiziño, el comando while verifica el pipeline compuesto por el who y por el grep y que será verdadero en cuanto el grep localice la palabra jefe en la salida del who. Así, el script dormirá durante 30 segundos mientras el jefe esté logado (Argh!). Cuando él se desconecte del servidor, el flujo del script saldra del loop y dará el tan ansiado mensaje de libertad.
 
Changed:
<
<
Cuando lo ejecuté adivina lo que aconteció?
>
>
Si lo ejecuto adivinas lo que pasa?
 
$ logaute.sh
Line: 141 to 141
 jefe pts/0 Jan 4 08:52 (10.2.4.144)
Changed:
<
<
O sea a cada 30 segundos seria enviado para mi pantalla la salida del grep, lo que no seria deseable ya que llenaría la pantalla del computador y el esperado mensaje podria pasar desapercebido. Para evitar eso ya sabemos que la salida del pipeline tiene que ser redireccionada para /dev/null.
>
>
Pues que cada 30 segundos es enviada a mi pantalla la salida del grep, lo que no es deseable ya que lleno la pantalla del computador y ademas el esperado mensaje podría pasar desapercibido. Para evitar eso ya sabemos que la salida del pipeline tiene que ser redireccionada hacia /dev/null.
 
$ cat logaute.sh
Line: 151 to 151
 do sleep 30 done
Changed:
<
<
echo El rompe se fue, no hesite, dé un exit y va enfrente
>
>
echo El rompe se fue, no te entretengas, date el piro y ves enfrentee
 
Changed:
<
<
Ahora quiero montar un script que reciba el nombre (y eventuales parámetros) de un programa que será ejecutado en background y que me informe de su término. Pero, para entender este ejemplo, primero tengo que mostar una nueva variable del sistema. Vea estos comandos directos en el prompt:
>
>
Ahora quiero montar un script que reciba el nombre (y eventuales parámetros) de un programa que será ejecutado en background y que me informe de su término. Pero, para entender este ejemplo, primero tengo que mostrar una nueva variable del sistema. Mira estos comandos escritos directamente en el prompt:
 
$ sleep 10&
Line: 166 to 166
 16317
Changed:
<
<
O sea, crié un proceso en background para dormir por 10 segundos, solamente para mostrar que la variable $! guarda el PID (Process IDentification) del último proceso en background, sin embargo, note que después de la línea del done, la variable continuó con el mismo valor.
>
>
O sea, lance un proceso en background que se ejecutara cada 10 segundos, solo para mostrar que la variable $! guarda el PID (Process IDentification) del último proceso en background, sin embargo, fíjate que después de la línea del done, la variable continuó con el mismo valor.
 
Changed:
<
<
Bien, sabiendo eso es más fácil de controlar cualquier proceso en background. Vea como:
>
>
Bien, sabiendo eso es más fácil de controlar cualquier proceso en background. Observa como:
 
$ cat monbg.sh
Line: 185 to 185
 echo Fin del Proceso $1
Changed:
<
<
Este script es bastante similar al anterior, pero tiene unos trucos más, vea: él tiene que ser ejecutado en background para no retener el prompt pero el $! será el del programa pasado como parámetro ya que fue colocado en background después del monbg.sh propriamente dicho. Note también la opción -q (quiet) del grep, sirve para tranformarlo en un comando silencioso, o sea, para que el grep trabaje en forma invisible. El mismo resultado podría ser obtenido si la línea fuera while ps | grep $! > /dev/null, como en los ejemplos que vimos hasta ahora.
>
>
Este script es bastante similar al anterior, pero tiene unos trucos más, mira: tiene que ser ejecutado en background para no retener el prompt pero el $! será el del programa pasado como parámetro ya que fue colocado en background después del monbg.sh propiamente dicho. Observa también la opción -q (quiet) del grep, sirve para transformarlo en un comando silencioso, o sea, para que el grep trabaje de forma invisible. Este mismo resultado podría ser obtenido si la línea fuera while ps | grep $! > /dev/null, como en los ejemplos que vimos hasta ahora.
 
Pinguim com placa de dica
Changed:
<
<
No se olvide: el Bash disponibiliza la variable $! que posee el PID (Process IDentification) del último proceso ejecutado en background.
>
>
No te olvides: el Bash dispone de la variable $! que posee el PID (Process IDentification) del último proceso ejecutado en background.
 
Changed:
<
<
Vamos a mejorar el musinc, que es nuestro programa para incluir registros en el archivo musicas, pero antes preciso enseñarte a capturar un dato de la pantalla, y ya voy avisando: solo voy a dar una pequeña parte del comando read (que es quien hace la captura de la pantalla) que sea lo suficiente para resolver este problema. En otra vuelta de chopp te voy a enseñar todo sobre el asunto, inclusive como formatar la pantalla, pero hoy estamos hablando sobre loops.
>
>
Vamos a mejorar el musinc, que es nuestro programa para incluir registros en el archivo musicas, pero antes necesito enseñarte a capturar un dato de la pantalla, y ya voy avisando: solo voy a dar una pequeña parte del comando read (que es quien hace la captura de la pantalla) que sea lo suficiente para resolver este problema. En otra vuelta de "chopp" te lo voy a enseñar todo del asunto, inclusive como formatear la pantalla, pero hoy estamos hablando sobre loops.
 
Changed:
<
<
La sintáxis del comando read que nos interesa por ahora es la siguiente:
>
>
La sintaxis del comando read que nos interesa por ahora es la siguiente:
 
$ read -p "prompt de lectura" var
Changed:
<
<
Donde prompt de lectura es el texto que quieres que aparezca escrito en la pantalla, y cuando el operador digitar el dato éste irá para la variable var. Por ejemplo:
>
>
Donde prompt de lectura es el texto que quieres que aparezca escrito en la pantalla, y cuando el operador escriba el dato éste irá a parar anla variable var. Por ejemplo:
 
$ read -p "Título del Álbun: " Tit
Changed:
<
<
Bien, uma vez entendido eso, vamos a la especificación de nuestro problema: haremos un programa que inicialmente leerá el nombre del álbum y en seguida hará un loop de lectura, extrayendo la música y el artista. Este loop termina cuando sea informada una música vacia, o sea, al ser solicitada la digitación de la música, el operador dá un simple <ENTER>. Para facilitar la vida del operador, vamos a ofrecer como default el mismo nome del artista de la música anterior (ya que es normal que el álbum sea todo del mismo artista) hasta que él desee alterarlo. Vamos a ver como quedó ahora:
>
>
Bien, una vez entendido eso, vamos a la especificación de nuestro problema: haremos un programa que inicialmente leerá el nombre del álbum y en seguida hará un loop de lectura, extrayendo la música y el artista. Este loop termina cuando se encuentre una música vacía, o sea, al ser solicitada la escritura de la música, el operador de un simple <ENTER>. Para facilitar la vida del operador, vamos a ofrecer como default el mismo nombre del artista de la música anterior (ya que es normal que el álbum sea todo del mismo artista) hasta que él desee alterarlo. Vamos a ver como quedó ahora:
 
$ cat musinc
Line: 238 to 238
 sort musicas -o musicas
Changed:
<
<
Este ejemplo, comienza con la lectura del título del álbun, que si no es informado, terminará la ejecución del programa. En seguida un grep procura en el inicio (^) de cada registro de músicas, el título informado seguido del separador (^) (que está precedido de una contrabarra (\) para protegerlo de la interpretación do Shell).
>
>
Este ejemplo, comienza con la lectura del título del álbum, y si no es introducido, terminará la ejecución del programa. En seguida un grep busca en el inicio (^) de cada registro de músicas, el título introducido seguido del separador (^) (que está precedido de una contrabarra (\) para protegerlo de la interpretación del Shell).
 
Changed:
<
<
Para leer los nombres de los artistas y las músicas del álbun, fue montado un loop de while simple, cuyo único destaque es el hecho de estar almacenando el artista de la música anterior en la variable $oArt que solamente tendrá su contenido alterado, cuando alguno de los datos sea informado para la variable $Art, o sea, cuando no tecleó un simple <ENTER> para mantener el artista anterior.
>
>
Para leer los nombres de los artistas y las músicas del álbum, fue montado un loop de while simple, que lo único que tiene a destacar es el hecho de estar almacenando el artista de la música anterior en la variable $oArt que solamente tendrá su contenido alterado, cuando alguno de los datos sea introducido en la variable $Art, o sea, cuando no se teclee un simple <ENTER> para mantener el artista anterior.
 
Changed:
<
<
Lo que fue visto hasta ahora sobre el while fue muy poco. Este comando es muy utilizado, principalmente para lectura de archivos, sin embargo nos faltan conocimientos para continuar. Después que aprendamos a leer, veremos esta instrucción más a fondo.
>
>
Lo viste hasta ahora sobre el while fue muy poco. Este comando es muy utilizado, principalmente para lectura de archivos, sin embargo nos faltan conocimientos para continuar. Después que aprendamos a leer, veremos esta instrucción más a fondo.
 
Pinguim com placa de dica
Changed:
<
<
Lectura del archivo significa leer uno a uno todos los registros, lo que es siempre una operación lenta. Esté atento para no usar el while cuando su uso puede ser evitado. El Shell tiene recursos como el sed y la familia grep que buscan enlos archivos de forma optimizada sin ser necesario el uso de comandos de loop para hacerlo registro a registro (o hasta palabra a palabra).
>
>
Lectura del archivo significa leer uno a uno todos los registros, lo que es siempre una operación lenta. Estate atento de no usar el while cuando su uso puede ser evitado. El Shell tiene recursos como el sed y la familia grep que buscan en los archivos de forma optimizada sin ser necesario el uso de comandos de loop para hacerlo registro a registro (o hasta palabra a palabra).
 

El comando until

Changed:
<
<
El comando until funciona exactamente igual al while, sin embargo al revés. Dije todo pero no dije nada, no es cierto? Es lo siguiente: ambos verifican comandos; ambos poseem la misma sintáxis y ambos actuan en loop, sin embargo, en cuanto el while ejecuta el bloque de intruciones del loop en cuanto un comando sea bien ejecutado, el until ejecuta el bloque del loop hasta que el comando sea bien ejecutado. Parece una diferencia insignificante, pero en cambio ella es fundamental.
>
>
El comando until funciona exactamente igual al while, sin embargo al revés. Dije todo pero no dije nada, no es cierto? Es lo siguiente: ambos verifican comandos; ambos poseen la misma sintaxis y ambos actuan en loop, sin embargo, mientras el while ejecuta el bloque de instrucciones del loop mientras un comando este bien ejecutado, el until ejecuta el bloque del loop hasta que el comando este bien ejecutado. Parece una diferencia insignificante, pero en cambio es fundamental.
 
Changed:
<
<
La sintáxis del comando es practicamente la misma del while. Vea:
>
>
La sintáxis del comando es practicamente la misma del while. Observa:
 
    until comando
Line: 269 to 269
  Como te dije, el while y el until funcionan de forma antagónica lo cual es muy fácil de demostrar: en una guerra siempre que se inventa una arma, el enemigo busca una solución para neutralizarla. Basado en este principio de la guerra es que mi jefe, creó en el mismo servidor que yo ejecutaba el logaute.sh un script para controlar el horário de mi llegada.
Changed:
<
<
Un dia dió un problema en la red, y él me pedió para dar una mirada en su micro y me dejó solo en su sala. Inmediatamente comencé a revisar sus archivos - porque guerra es guerra - y vea lo que descubrí:
>
>
Un dia ocurrió un problema en la red, y él me pidió que echara una mirada en su ordenador y me dejó solo en su sala. Inmediatamente comencé a revisar sus archivos - porque guerra es guerra - y mira lo que descubrí:
 
$cat llegada.sh
Line: 282 to 282
 echo $(date "+ El %d/%m a las %H:%Mh") >> haragán.log
Changed:
<
<
Que cara dura! Él estaba montando un log con los horarios en que yo llegaba, y además llamó el archivo que me controlaba de haragán.log! Que será que quiso decir con eso?
>
>
Que cara dura! Él estaba montando un log con los horarios en que yo llegaba, y además llamó el archivo que me controlaba de haragán.log! Que será lo que quiso decir con eso?
 
Changed:
<
<
En este script, el pipeline who | grep julio, será bien ejecutado solamente cuando julio sea encontrado en el comando who, o sea, cuando yo me "logue" en el servidor. Hasta que eso pase, el comando sleep, que forma el bloque de instrucciones del until, pondrá el programa en espera por 30 segundos. Cuando este loop se cierre, será enviado un mensaje para el haragán.log (ARGHH!). Suponiendo que en el dia 20/01 yo me logué a las 11:23 horas, el mensaje sería el siguiente:
>
>
En este script, el pipeline who | grep julio, será bien ejecutado solamente cuando julio sea encontrado en el comando who, o sea, cuando yo me "logue" en el servidor. Hasta que eso pase, el comando sleep, que forma el bloque de instrucciones del until, pondrá el programa en espera por 30 segundos. Cuando este loop se cierre, será enviado un mensaje hacia el haragán.log (ARGHH!). Suponiendo que el dia 20/01 yo me loguease a las 11:23 horas, el mensaje sería el siguiente:
       El 20/01 a las 11:23h
Changed:
<
<
Cuando vamos a catastrar músicas, lo ideal sería que pudiésemos catastrar diversos CDs, y en la última versión que hicimos del musinc, eso no ocurre, a cada CD que catastramos el programa termina. Veamos como mejorarlo:
>
>
Cuando vamos a buscar introducir, lo ideal sería que pudiésemos introducir diversos CDs, y en la última versión que hicimos del musinc, eso no ocurre, a cada CD que introducimos el programa termina. Veamos como mejorarlo:
 
$ cat musinc
Line: 306 to 306
  else if grep "^$Tit\^" musicas > /dev/null then
Changed:
<
<
echo Este álbum ya está catastrado
>
>
echo Este álbum ya está introducido
  exit 1 fi Reg="$Tit^"
Line: 329 to 329
 done
Changed:
<
<
En esta versión, fué agregado un loop mayor antes de la lectura del título, que solo terminará cuando la variable $Para deje de estar vacía. En el caso de que el título del álbum no sea informado, la variable $Para recibirá valor (en este caso coloqué 1 pero podría haber colocado cualquier cosa. Lo importante es que no sea vacía) para salir de este loop, y terminar el programa. En el resto, el script es idéntico a la versión anterior.
>
>
En esta versión, fué agregado un loop mayor antes de la lectura del título, que solo terminará cuando la variable $Para deje de estar vacía. En el caso de que el título del álbum no se encuentre, la variable $Para recibirá valor (en este caso coloqué 1 pero podría haber colocado cualquier cosa. Lo importante es que no este vacía) para salir de este loop, y terminar el programa. En el resto, el script es idéntico a la versión anterior.
 

Atajos en loop

Line: 349 to 349
 Fluxograma
Changed:
<
<
Dudo mucho que nunca hayas borrado um archivo y enseguida no te diste un golpe en la cabeza, maldiciéndote porque no debías haberlo hecho. Claro, en la décima vez que hice esa burrada, crié un script para simular una cesta de basura, o sea, cuando mando borrar uno (o varios) archivo(s), el programa "finge" que lo borró, pero en realidad lo que hizo fue mandarlo(s) para el diretório /tmp/LoginName_del_usuario. Llamé este programa de erreeme y en el /etc/profile coloqué la siguiente línea:
>
>
Dudo mucho que nunca hayas borrado un archivo y enseguida no te dieras un golpe en la cabeza, maldiciéndote porque no debías haberlo hecho. Claro, pues yo la décima vez que hice esa burrada, cree un script para simular una cesta de basura, o sea, cuando mando borrar uno (o varios) archivo(s), el programa "finge" que lo borró, pero en realidad lo que hizo fue mandarlo(s) para el diretório /tmp/LoginName_del_usuario. Llamé este programa de erreeme y en el /etc/profile coloqué la siguiente línea:
       alias rm=erreeme
Line: 359 to 359
 $ cat erreeme #/bin/bash #
Changed:
<
<
# Salvando Copia de Archivo Antes de Borrarlo
>
>
# Salvando Copia del Archivo Antes de Borrarlo
 #

if [ $# -eq 0 ] # Tiene que haber uno o mas archivos para borrar

Line: 403 to 403
  then echo $Arch quedará sin copia de seguridad rm -i $Arch # Pregunta antes de borrar
Changed:
<
<
[ -f $Arch ] || echo $Arch borrado # Será que el usuario borró?
>
>
[ -f $Arch ] || echo $Arch borrado # Será que el usuario lo borró?
  continue fi

Line: 415 to 415
 exit $Erro # Paso eventual número de error para el código de retorno
Changed:
<
<
Como puedes ver, la mayor parte del script es formada por pequeñas críticas a los parámetros informados, pero como el script puede haber recibido diversos archivos para borrar, a cada archivo que no se encaja dentro del especificado, hay un continue, para que la secuencia vuelva para el loop del for de forma de recibir otros archivos.
>
>
Como puedes ver, la mayor parte del script es formada por pequeñas críticas a los parámetros hallados, pero como el script puede haber recibido diversos archivos para borrar, a cada archivo que no se encaja dentro del especificado, hay un continue, para que la secuencia vuelva para el loop del for de forma que pueda recibir otros archivos.
 
Changed:
<
<
Cuando estás en Windows (con perdón de la mala palabra) y tratas de borrar aquella cantidad de basura con nombres extraños como HD04TG.TMP, si da un error en uno de ellos, los otros no serán borrados, no es así? Entonces, el continue fue usado para evitar que un barbaridad de estas ocurra, o sea, aunque dé un error en el borrado de un archivo, el programa continuará borrando los otros que fueron pasados.
>
>
Cuando estás en Windows (con perdón de la mala palabra) y tratas de borrar aquella cantidad de basura con nombres extraños como HD04TG.TMP, si te da un error en uno de ellos, los otros no serán borrados, no es así? Entonces, el continue fue usado para evitar que un barbaridad de estas ocurra, o sea, aunque dé un error en el borrado de un archivo, el programa continuará borrando los otros que le fueron pasados.
 
Changed:
<
<
     - Me parece que a esta altura ya debes estar curioso para ver el programa que restaura el archivo borrado, no es así? Entonces, ahí va un desafio: hácelo en casa y me lo traes para discutirlo en nuestro próximo encuentro aqui en el bar.
>
>
     - Me parece que a esta altura ya debes tener curiosidad por ver el programa que restaura el archivo borrado, no es así? Entonces, ahí va un desafio: hazlo en casa y me lo traes para discutirlo en nuestro próximo encuentro aqui en el bar.
       - Caramba, me parece que en ese voy a fracasar, no sé ni como comenzar...
Changed:
<
<
     - Mi amigo, este programa es como todo lo que se hace en Shell, extremamente fácil, es para ser hecho en no más de 10 líneas. No te olvides que es archivo está grabado en /tmp/$LOGNAME y que su última línea es el directorio en que estaba antes de ser "borrado". Tambiém no te olvides de criticar si fue pasado el nombre del archivo a ser removido.
>
>
     - Amigo mio, este programa es como todo lo que se hace en Shell, extremamente fácil, es para ser hecho en no más de 10 líneas. No te olvides que el archivo borrado está grabado en /tmp/$LOGNAME y que su última línea es el directorio en que estaba antes de ser "borrado". Tampoco te olvides de comprobar si fue pasado el nombre del archivo a ser borrado.
       - En fin, voy a tratar, pero no sé...
Changed:
<
<
     - Tenga fé, te estoy diciendo que es fácil! Cualquier duda me pasas un e-mail para julio.neves@gmail.com. Ahora basta de conversa que ya estoy de garganta seca de tanto hablar. Me acompañas en el próximo chopp o ya vas a salir corriendo para hacer el script que pasé?
>
>
     - Ten fé hombre, te estoy diciendo que es fácil! Cualquier duda me pasas un e-mail para julio.neves@gmail.com. Ahora basta de conversación que ya estoy con la garganta seca de tanto hablar. Me acompañas en el próximo "chopp" o vas a salir corriendo para hacer el script que pasé?
       - Déjame pensar un poco...
Changed:
<
<
     - Mozo, trae otro chopp en cuanto él piensa!
>
>
     - Mozo, trae otro "chopp" mientras él piensa!
  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 julio.neves@uniriotec.br para informarse.

Revision 403 Feb 2008 - JulioNeves

Line: 1 to 1
Changed:
<
<

Conversa de Bar Parte VI

>
>

Conversación de Bar Parte VI

 

Revision 313 Feb 2007 - JulioNeves

Line: 1 to 1
 

Conversa de Bar Parte VI

Line: 435 to 435
  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 julio.neves@uniriotec.br para informarse.
Changed:
<
<
Gracias y hasta la próxima!
>
>
Gracias y hasta la próxima
  -- HumbertoPina - 28 Nov 2006

Revision 217 Jan 2007 - JulioNeves

Line: 1 to 1
 

Conversa de Bar Parte VI

Revision 111 Jan 2007 - JulioNeves

Line: 1 to 1
Added:
>
>

Conversa de Bar Parte VI

Comandos de Loop o Lazo (Continuación)

     - Que tal mi amigo, como anda? Ya está sabiendo todo acerca del comando for? Te dejé un ejercicio de deberes, si no estoy equivocado, era para contar la cantidad de palabras de un archivo... Lo hiciste?

     - Claro! Estoy entusiasmando con ese lenguaje del shell, lo hice de la forma que me pediste, o sea sin usar el comando wc porque si no era mucho más fácil. Mira lo que hicei...

     - Epa! Un momento! Realmente estás entusiasmando con el lenguaje, pero yo estoy deseando tomar un chopp. Chico!, traeme dos por favor. Uno sin espuma, como siempre!

     - Como te iba diciendo, vé lo que hice. Es muy fácil...

$ cat contpal.sh #!/bin/bash # Script meramente pedagógico cuya # función es contar la cantidad de palabras # de un archivo. Se supone que las # palabras están separadas entre sí # por espacio, o .

if [ $# -ne 1 ] then echo uso: $0 /camino/del/archivo exit 2 fi Cont=0 for Palabra in $(cat $1) do Cont=$((Cont+1)) done echo El archivo $1 tiene $Cont palabras.

O sea, el programa comienza como siempre verificando si el pasaje de parámetros fue correcto, en seguida el comando for se encarga de agarrar cada una de las palabras (recuerda que el $IFS padrón (default) es espacio, <TAB> y <ENTER>, que es exactamente lo que deseamos para separar las palabras), incrementando la variable $Cont.

Vamos a recordar como es el archivo ArchDelDOS.txt.

$ cat ArqDoDOS.txt Este archivo fue generado por el DOS/Rwin y fue bajado por un ftp mal hecho.

Ahora vamos a testar el programa pasando este archivo como parámetro:

$ contpal.sh ArchDelDOS.txt El archivo ArchDelDOS.txt tiene 15 palabras

     - Muy bien! funcionó correctamente!

Un Poco más de for y Matemática

Volviendo a nuestro tema, la última vez que estuvimos aqui, terminamos nuestra conversación mostrando el loop de for a seguir:

    for ((; i<=9;))
    do
        let i++
        echo -n "$i "
    done

Una vez que llegamos a este punto, creo que sea bastante interesante citar que el Shell trabaja con el concepto de "Expansión Aritmética" (Arithmetic Expansion) que es accionado por una construcción de la forma

     $((expresión))

o

     let expressión

En el último for citado, usé la expansión de las dos formas, pero no poderíamos seguir adelante sin saber que la expresión puede ser una de las listadas a seguir:

Expansión Aritmética
||   O lógico
  Expresión     Resultado  
id++ id--   pós-incremento y pós-decremento de variables
++id -–id   pré-incremento y pré-decremento de variables
**   exponenciación
* / %   multiplicación, división, resto de la división
+ -   adición, substraccuión
<= >= < >   comparación
== !=   igualdad, desigualdad
&&   Y lógico

     - Y piensas que la conversación sobre loop (o lazo) se encierra en el comando for? Craso engaño amigo, vamos a partir de ahora a ver dos más.

El comando while

Todos los programadores conocen este comando, ya que es común a todas los lenguajes y en ellos lo que normalmente ocurre, es que un bloque de comandos es ejecutado, en cuanto que (en cuanto que en inglés es while) una determinada condición sea verdadera. Pues bien, esto es lo que ocurre en otros lenguajes! En programación Shell, el bloque de comandos es ejecutado en cuanto que un comando sea verdadero. Y es claro, si quisiera verificar una condición use el comando while junto con el comando test, exactamente como aprendiste a hacer en el if, recuerdas?

Entonces, la sintáxis del comando queda de la siguiente forma:

    while comando
    do
        cmd1
        cmd2
        ...
        cmdn
    done

y de esta forma el bloque de comandos formado por las instrucciones cmd1, cmd2,... y cmdn será ejecutado en cuanto que la ejecución de la instrucción comando sea ejecutada con suceso.

Suponga la seguinte escena: tengo una tremenda gata esperandome y estoy preso en el trabajo in poder salir porque mi jefe, que es un tremendo rompre cocos se encuentra todavia trabajando en su escritorio, que queda bien en medio de mi salida a la calle.

Él comenzó a quedar con las antenas (probablemente instaladas en su cabeza por la esposa) atentas, después de la quinta vez que me vió pasar por su puerta y ver que todavia estaba alli. Volví a mi mesa e hice un script en el servidor de esta forma:

$ cat logaute.sh #!/bin/bash

while who | grep jefe do sleep 30 done echo El rompe se fue, no hesite, dé un exit y va enfrente

En este scriptiziño, el comando while verifica el pipeline compuesto por el who y por el grep y que será verdadero en cuanto el grep localize la palabra jefe en la salida del who. Así, el script dormirá por 30 segundos en cuanto el jefe esté logado (Argh!). Cuando él se desconecte del servidor, el flujo del script salirá del loop y dará el tan ansiado mensaje de libertad.

Cuando lo ejecuté adivina lo que aconteció?

$ logaute.sh jefe pts/0 Jan 4 08:46 (10.2.4.144) jefe pts/0 Jan 4 08:47 (10.2.4.144) ... jefe pts/0 Jan 4 08:52 (10.2.4.144)

O sea a cada 30 segundos seria enviado para mi pantalla la salida del grep, lo que no seria deseable ya que llenaría la pantalla del computador y el esperado mensaje podria pasar desapercebido. Para evitar eso ya sabemos que la salida del pipeline tiene que ser redireccionada para /dev/null.

$ cat logaute.sh #!/bin/bash

while who | grep jefe > /dev/null do sleep 30 done echo El rompe se fue, no hesite, dé un exit y va enfrente

Ahora quiero montar un script que reciba el nombre (y eventuales parámetros) de un programa que será ejecutado en background y que me informe de su término. Pero, para entender este ejemplo, primero tengo que mostar una nueva variable del sistema. Vea estos comandos directos en el prompt:

$ sleep 10& [1] 16317 $ echo $! 16317 [1]+ Done sleep 10 $ echo $! 16317

O sea, crié un proceso en background para dormir por 10 segundos, solamente para mostrar que la variable $! guarda el PID (Process IDentification) del último proceso en background, sin embargo, note que después de la línea del done, la variable continuó con el mismo valor.

Bien, sabiendo eso es más fácil de controlar cualquier proceso en background. Vea como:

$ cat monbg.sh #!/bin/bash

# Ejecuta y controla un # proceso en background

$1 & # Coloca en backgroud while ps | grep -q $! do sleep 5 done echo Fin del Proceso $1

Este script es bastante similar al anterior, pero tiene unos trucos más, vea: él tiene que ser ejecutado en background para no retener el prompt pero el $! será el del programa pasado como parámetro ya que fue colocado en background después del monbg.sh propriamente dicho. Note también la opción -q (quiet) del grep, sirve para tranformarlo en un comando silencioso, o sea, para que el grep trabaje en forma invisible. El mismo resultado podría ser obtenido si la línea fuera while ps | grep $! > /dev/null, como en los ejemplos que vimos hasta ahora.

Pinguim com placa de dica No se olvide: el Bash disponibiliza la variable $! que posee el PID (Process IDentification) del último proceso ejecutado en background.

Vamos a mejorar el musinc, que es nuestro programa para incluir registros en el archivo musicas, pero antes preciso enseñarte a capturar un dato de la pantalla, y ya voy avisando: solo voy a dar una pequeña parte del comando read (que es quien hace la captura de la pantalla) que sea lo suficiente para resolver este problema. En otra vuelta de chopp te voy a enseñar todo sobre el asunto, inclusive como formatar la pantalla, pero hoy estamos hablando sobre loops.

La sintáxis del comando read que nos interesa por ahora es la siguiente:

$ read -p "prompt de lectura" var

Donde prompt de lectura es el texto que quieres que aparezca escrito en la pantalla, y cuando el operador digitar el dato éste irá para la variable var. Por ejemplo:

$ read -p "Título del Álbun: " Tit

Bien, uma vez entendido eso, vamos a la especificación de nuestro problema: haremos un programa que inicialmente leerá el nombre del álbum y en seguida hará un loop de lectura, extrayendo la música y el artista. Este loop termina cuando sea informada una música vacia, o sea, al ser solicitada la digitación de la música, el operador dá un simple <ENTER>. Para facilitar la vida del operador, vamos a ofrecer como default el mismo nome del artista de la música anterior (ya que es normal que el álbum sea todo del mismo artista) hasta que él desee alterarlo. Vamos a ver como quedó ahora:

$ cat musinc #!/bin/bash # Catastra CDs (versión 4) # clear read -p "Título del Álbun: " Tit [ "$Tit" ] || exit 1 # Fin de la ejecución si el título= vacio if grep "^$Tit\^" musicas > /dev/null then echo Este álbum ya está catastrado exit 1 fi Reg="$Tit^" Cont=1 oArt= while true do echo Datos de la pista $Cont: read -p "Música: " Mus [ "$Mus" ] || break # Sale si vacio read -p "Artista: $oArt // " Art [ "$Art" ] && oArt="$Art" # Si vacio Art anterior Reg="$Reg$oArt~$Mus:" # Montando el registro Cont=$((Cont + 1)) # La linea anterior también podria ser ((Cont++)) done echo "$Reg" >> musicas sort musicas -o musicas

Este ejemplo, comienza con la lectura del título del álbun, que si no es informado, terminará la ejecución del programa. En seguida un grep procura en el inicio (^) de cada registro de músicas, el título informado seguido del separador (^) (que está precedido de una contrabarra (\) para protegerlo de la interpretación do Shell).

Para leer los nombres de los artistas y las músicas del álbun, fue montado un loop de while simple, cuyo único destaque es el hecho de estar almacenando el artista de la música anterior en la variable $oArt que solamente tendrá su contenido alterado, cuando alguno de los datos sea informado para la variable $Art, o sea, cuando no tecleó un simple <ENTER> para mantener el artista anterior.

Lo que fue visto hasta ahora sobre el while fue muy poco. Este comando es muy utilizado, principalmente para lectura de archivos, sin embargo nos faltan conocimientos para continuar. Después que aprendamos a leer, veremos esta instrucción más a fondo.

Pinguim com placa de dica Lectura del archivo significa leer uno a uno todos los registros, lo que es siempre una operación lenta. Esté atento para no usar el while cuando su uso puede ser evitado. El Shell tiene recursos como el sed y la familia grep que buscan enlos archivos de forma optimizada sin ser necesario el uso de comandos de loop para hacerlo registro a registro (o hasta palabra a palabra).

El comando until

El comando until funciona exactamente igual al while, sin embargo al revés. Dije todo pero no dije nada, no es cierto? Es lo siguiente: ambos verifican comandos; ambos poseem la misma sintáxis y ambos actuan en loop, sin embargo, en cuanto el while ejecuta el bloque de intruciones del loop en cuanto un comando sea bien ejecutado, el until ejecuta el bloque del loop hasta que el comando sea bien ejecutado. Parece una diferencia insignificante, pero en cambio ella es fundamental.

La sintáxis del comando es practicamente la misma del while. Vea:

    until comando
    do
        cmd1
        cmd2
        ...
        cmdn
    done

Y así el bloque de comandos formado por las instruciones cmd1, cmd2,... y cmdn es ejecutado hasta que la ejecución de la instrucción comando sea bien ejecutada.

Como te dije, el while y el until funcionan de forma antagónica lo cual es muy fácil de demostrar: en una guerra siempre que se inventa una arma, el enemigo busca una solución para neutralizarla. Basado en este principio de la guerra es que mi jefe, creó en el mismo servidor que yo ejecutaba el logaute.sh un script para controlar el horário de mi llegada.

Un dia dió un problema en la red, y él me pedió para dar una mirada en su micro y me dejó solo en su sala. Inmediatamente comencé a revisar sus archivos - porque guerra es guerra - y vea lo que descubrí:

$cat llegada.sh #!/bin/bash

until who | grep julio do sleep 30 done echo $(date "+ El %d/%m a las %H:%Mh") >> haragán.log

Que cara dura! Él estaba montando un log con los horarios en que yo llegaba, y además llamó el archivo que me controlaba de haragán.log! Que será que quiso decir con eso?

En este script, el pipeline who | grep julio, será bien ejecutado solamente cuando julio sea encontrado en el comando who, o sea, cuando yo me "logue" en el servidor. Hasta que eso pase, el comando sleep, que forma el bloque de instrucciones del until, pondrá el programa en espera por 30 segundos. Cuando este loop se cierre, será enviado un mensaje para el haragán.log (ARGHH!). Suponiendo que en el dia 20/01 yo me logué a las 11:23 horas, el mensaje sería el siguiente:

     El 20/01 a las 11:23h

Cuando vamos a catastrar músicas, lo ideal sería que pudiésemos catastrar diversos CDs, y en la última versión que hicimos del musinc, eso no ocurre, a cada CD que catastramos el programa termina. Veamos como mejorarlo:

$ cat musinc #!/bin/bash # Catastra CDs (versión 5) # Para= until [ "$Para" ] do clear read -p "Título del Álbum: " Tit if [ ! "$Tit" ] # Si titulo vacio... then Para=1 # Activé flag de salida else if grep "^$Tit\^" musicas > /dev/null then echo Este álbum ya está catastrado exit 1 fi Reg="$Tit^" Cont=1 oArt= while [ "$Tit" ] do echo Dados de la pista $Cont: read -p "Música: " Mus [ "$Mus" ] || break # Sale si vacío read -p "Artista: $oArt // " Art [ "$Art" ] && oArt="$Art" # Si vacío Art anterior Reg="$Reg$oArt~$Mus:" # Montando registro Cont=$((Cont + 1)) # La linha anterior también podría ser ((Cont++)) done echo "$Reg" >> musicas sort musicas -o musicas fi done

En esta versión, fué agregado un loop mayor antes de la lectura del título, que solo terminará cuando la variable $Para deje de estar vacía. En el caso de que el título del álbum no sea informado, la variable $Para recibirá valor (en este caso coloqué 1 pero podría haber colocado cualquier cosa. Lo importante es que no sea vacía) para salir de este loop, y terminar el programa. En el resto, el script es idéntico a la versión anterior.

Atajos en loop

No siempre un ciclo de programa, comprendido entre un do y un done, sale por la puerta del frente. En algunas oportunidades, tenemos que colocar un comando que aborte de forma controlada este loop. Al contrario, algunas veces deseamos que el fluxo de ejecución del programa vuelva antes de llegar al done. Para esto, tenemos respectivamente, los comandos break (que ya vimos rápidamente en los ejemplos del comado while) y continue, que funcionan de la siguiente forma:

Lo que no habia mencionado anteriormente es que en sus sintáxis genéricas, aparecen de la siguiente forma:

     break [ctd loop]

y

     continue [ctd loop]

Donde ctd loop representa la cantidad de loops internos sobre los que estos comandos van a actuar. Su valor default es 1.

Fluxograma

Dudo mucho que nunca hayas borrado um archivo y enseguida no te diste un golpe en la cabeza, maldiciéndote porque no debías haberlo hecho. Claro, en la décima vez que hice esa burrada, crié un script para simular una cesta de basura, o sea, cuando mando borrar uno (o varios) archivo(s), el programa "finge" que lo borró, pero en realidad lo que hizo fue mandarlo(s) para el diretório /tmp/LoginName_del_usuario. Llamé este programa de erreeme y en el /etc/profile coloqué la siguiente línea:

     alias rm=erreeme

El programa era así:

$ cat erreeme #/bin/bash # # Salvando Copia de Archivo Antes de Borrarlo #

if [ $# -eq 0 ] # Tiene que haber uno o mas archivos para borrar then echo "Erro -> Uso: erreeme arch [arch] ... [arch]" echo " El uso de metacaracteres es permitido. Ej. erreeme arch*" exit 1 fi

MiDir="/tmp/$LOGNAME" # Variable del sist. Contiene el nombre del usuario. if [ ! -d $MiDir ] # Si no exister mi directorio bajo el /tmp... then mkdir $MiDir # Voy a crearlo fi

if [ ! -w $MiDir ] # Si no puedo grabar en el directorio... then echo Imposible grabar archivos en $MiDir. Cambie el permiso... exit 2 fi

Erro=0 # Variable para indicar el cod. de retorno del prg for Arch # For sin el "in" recibe los parámetros pasados do if [ ! -f $Arch ] # Si este archivo no existe... then echo $Arch no existe. Erro=3 continue # Vuelve para el comando for fi

DirOrig=`dirname $Arch` # Cmd. dirname informa nombre del dir de $Arch if [ ! -w $DirOrig ] # Verifica permiso de grabación en el directorio then echo Sin permiso de borrar en el directorio de $Arch Erro=4 continue # Vuelve para el comando for fi

if [ "$DirOrig" = "$MiDir" ] # Si estoy "vaciando la basurera"... then echo $Arch quedará sin copia de seguridad rm -i $Arch # Pregunta antes de borrar [ -f $Arch ] || echo $Arch borrado # Será que el usuario borró? continue fi

cd $DirOrig # Guardo al final del archivo su directorio pwd >> $Arch # original para usarlo en un script de undelete mv $Arch $MiDir # Grabo y borro echo $Arch borrado done exit $Erro # Paso eventual número de error para el código de retorno

Como puedes ver, la mayor parte del script es formada por pequeñas críticas a los parámetros informados, pero como el script puede haber recibido diversos archivos para borrar, a cada archivo que no se encaja dentro del especificado, hay un continue, para que la secuencia vuelva para el loop del for de forma de recibir otros archivos.

Cuando estás en Windows (con perdón de la mala palabra) y tratas de borrar aquella cantidad de basura con nombres extraños como HD04TG.TMP, si da un error en uno de ellos, los otros no serán borrados, no es así? Entonces, el continue fue usado para evitar que un barbaridad de estas ocurra, o sea, aunque dé un error en el borrado de un archivo, el programa continuará borrando los otros que fueron pasados.

     - Me parece que a esta altura ya debes estar curioso para ver el programa que restaura el archivo borrado, no es así? Entonces, ahí va un desafio: hácelo en casa y me lo traes para discutirlo en nuestro próximo encuentro aqui en el bar.

     - Caramba, me parece que en ese voy a fracasar, no sé ni como comenzar...

     - Mi amigo, este programa es como todo lo que se hace en Shell, extremamente fácil, es para ser hecho en no más de 10 líneas. No te olvides que es archivo está grabado en /tmp/$LOGNAME y que su última línea es el directorio en que estaba antes de ser "borrado". Tambiém no te olvides de criticar si fue pasado el nombre del archivo a ser removido.

     - En fin, voy a tratar, pero no sé...

     - Tenga fé, te estoy diciendo que es fácil! Cualquier duda me pasas un e-mail para julio.neves@gmail.com. Ahora basta de conversa que ya estoy de garganta seca de tanto hablar. Me acompañas en el próximo chopp o ya vas a salir corriendo para hacer el script que pasé?

     - Déjame pensar un poco...

     - Mozo, trae otro chopp en cuanto él piensa!

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 julio.neves@uniriotec.br para informarse.

Gracias y hasta la próxima!

-- HumbertoPina - 28 Nov 2006

 
This site is powered by FoswikiCopyright © 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