\
for?. Te dejé un ejercicio de deberes, y 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 hice...
- 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!
- Como te iba diciendo, mira lo que hice. Es muy fácil...
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.
for y Matemática for a continuación:
for ((; i<=9;))
do
let i++
echo -n "$i "
done
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))
o
let expressión
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:
| 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 |
for, estas en un gran error amigo, vamos a partir de ahora a ver dos más.
while while junto con el comando test, exactamente como aprendiste a hacer en el if, recuerdas?
Entonces, la sintaxis 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 éxito.
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.
É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:
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.
Si lo ejecuto adivinas lo que pasa?
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.
$! 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.
Bien, sabiendo eso es más fácil de controlar cualquier proceso en background. Observa como:
$! 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.
No te olvides: el Bash dispone de la variable $! que posee el PID (Process IDentification) del último proceso ejecutado en background.
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.
La sintaxis del comando read que nos interesa por ahora es la siguiente:
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:
<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:
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).
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.
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.
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).
until 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.
La sintáxis del comando es practicamente la misma del while. Observa:
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 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í:
haragán.log! Que será lo 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 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
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:
$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.
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.
erreeme y en el /etc/profile coloqué la siguiente línea:
alias rm=erreeme
El programa era así:
continue, para que la secuencia vuelva para el loop del for de forma que pueda 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 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.
- 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...
- 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é...
- 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...
- 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.
Gracias y hasta la próxima
-- HumbertoPina - 28 Nov 2006
(CC) 2010 Pelos Frequentadores do Bar do Júlio Neves.