Difference: TWikiBarConversa005 (1 vs. 6)

Revision 614 Feb 2012 - MarioSilva

Line: 1 to 1
 

Conversación de bar Parte V

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

-- HumbertoPina - 20 Oct 2006

Added:
>
>

Revision 504 Feb 2008 - CollonsTorre

Line: 1 to 1
 

Conversación de bar Parte V

Changed:
<
<
     - Y ahí amigo! Ordenó sus ideas? Su cabeza ya se fundió, o todavia aguanta más Shell?
>
>
     - Que hay amigo! Ordenaste ya tus ideas?, Se fundió ya tu cabeza, o todavía aguanta más Shell?
 
Changed:
<
<
     - Aguanto, claro! Estoy gustando mucho! Me gustó tanto que hasta me esmeré en el ejercício que me dejó. Te acuerdas que me pediste para hacer un programa que recebiría como parámetro el nombre de un archivo y que quando ejecutado salvaría este archivo con el nombre original seguido de un til (~) y colocaría este archivo dentro do vi?
>
>
     - Aguanto, claro! Me esta gustando mucho! Me gustó tanto que hasta me esmeré en el ejercicio que me dejaste. Te acuerdas que me pediste que hiciera un programa que recibiría como parámetro el nombre de un archivo y que cuando se ejecutara salvara este archivo con el nombre original seguido de una tilde (~) ademas de colocarlo dentro del vi?
 
Changed:
<
<
     - Claro que me acuerdo, muéstrame y explica como lo hiciste.
>
>
     - Claro que me acuerdo, muéstramelo y explica como lo hiciste.
 
$ cat vira
Line: 46 to 46
       - Bárbaro, muy bien! Pero dime una cosa: porque terminaste el programa con un exit 0?
Changed:
<
<
     - Ahhh! Descubri que el número después del exit dará el código de retorno del programa (o $?, te acuerdas?), y de esta forma, como fue todo bien ejecutado, se cerraría con el $? = 0. Sin embargo, si observas, verás que en el caso de que el programa no haya recibido el nombre del archivo o en el caso de que el operador no tuviera privilégios de grabación sobre este arquivo, el código de retorno ($?) sería diferente do cero.
>
>
     - Ahhh! Descubri que el número después del exit da el código de retorno del programa (o $?, te acuerdas?), y de esta forma, si todo se ejecuto bien, se cerraría con el $? = 0. Sin embargo, si observas, verás que en el caso de que el programa no reciba el nombre del archivo o en el caso de que el operador no tenga privilegios de grabación sobre este archivo, el código de retorno ($?) sería diferente de cero.
       - Grande!, aprendiste bien, pero es bueno dejar claro que el exit 0, simplemente exit, o no colocar exit, producen igualmente un código de retorno ($?) igual a cero, si el programa fue bien ejecutado. Ahora vamos a hablar sobre las instrucciones de loop o lazo, pero antes voy a pasar el concepto de bloque de programa.
Changed:
<
<
Hasta ahora ya vimos algunos bloques de programa, como cuando te mostré un ejemplo para hacer un cd para adentro de un directório, el que era así:
>
>
Hasta ahora ya vimos algunos bloques de programa, como cuando te mostré un ejemplo para hacer un cd hacia dentro de un directorio, y que era así:
 
cd lmb 2> /dev/null ||
Line: 60 to 60
  }
Changed:
<
<
El fragmento contenido entre las dos llaves ({}), forman un bloque de comandos. También en este ejercício que acabamos de ver, en que salvamos el archivo antes de editarlo, existen varios bloque de comandos comprendidos entre los then y los fi del if.
>
>
El fragmento contenido entre las dos llaves ({}), forma un bloque de comandos. También en este ejercicio que acabamos de ver, en que salvamos el archivo antes de editarlo, existen varios bloque de comandos comprendidos entre los then y los fi del if.
  Un bloque de comandos también puede estar dentro de un case, o entre un do y un done.

     - Espera ahí Julio, que do y done son esos, no me acuerdo de que hayas hablado de ellos y mira que estoy prestando mucha atención...

Changed:
<
<
     - Claro, todavia no habia hablado porque no habia llegado el momento adecuado. Todas las instrucciones de loop o lazo, ejecutan los comandos del bloque comprendido entre el do y el done.
>
>
     - Claro, todavía no había hablado de ellos porque no había llegado el momento adecuado. Todas las instrucciones de loop o lazo, ejecutan los comandos del bloque comprendido entre el do y el done.
 

Comandos de Loop (o lazo)

Changed:
<
<
Las instruciones de loop o lazo son el for, el while y el until que pasaré a explicarte una a una a partir de hoy.
>
>
Las instrucciones de loop o lazo son el for, el while y el until que pasaré a explicarte una a una a partir de hoy.
 

El comando for

Changed:
<
<
Si ya estás habituado a programar, con seguridad conoces el comando for, pero lo que no sabes es que el for, que es una instrucción intrínseca del Shell (esto significa que el código fuente del comando es parte del código fuente del Shell, o sea en buen idioma programés es un built-in), es mucho más poderoso que los semejantes de otras lenguajes.
>
>
Si ya estás habituado a programar, con seguridad conoces el comando for, pero lo que no sabes es que el for, que es una instrucción intrínseca del Shell (esto significa que el código fuente del comando es parte del código fuente del Shell, o sea en buen idioma "programés" es un built-in), es mucho más poderoso que los semejantes de otras lenguajes.
 
Changed:
<
<
Vamos a entender su sintáxis, primero en español y después como funciona realmente.
>
>
Vamos a entender su sintaxis, primero en español y después como funciona realmente.
 
    para var en val1 val2 ... valn
    haga
Line: 86 to 86
  hecho
Changed:
<
<
Donde la variable var asume cada uno de los valores de la lista val1 val2 ... valn y para cada uno de eses valores ejecuta el bloque de comandos formado por cmd1, cmd2 y cmdn
>
>
Donde la variable var asume cada uno de los valores de la lista val1 val2 ... valn y para cada uno de esos valores ejecuta el bloque de comandos formado por cmd1, cmd2 y cmdn
 
Changed:
<
<
Ahora que ya vimos el significado de la instrucción en español, veamos la sintáxis correcta:
>
>
Ahora que ya vimos el significado de la instrucción en español, veamos la sintaxis correcta:
 
Changed:
<
<

Primera sintáxis del comando for:

>
>

Primera sintaxis del comando for:

 
    for var in val1 val2 ... valn
Line: 101 to 101
  done
Changed:
<
<
Vamos directo para los ejemplos, a fin de entender el funcionamento de este comando. Vamos a escribir un script para listar todos los archivos de nuestro directório separados por dos puntos, pero vea primero:
>
>
Vamos directo a los ejemplos, a fin de entender el funcionamiento de este comando. Vamos a escribir un script para listar todos los archivos de nuestro directorio separados por dos puntos, pero mira primero:
 
$ echo * ArchDoDOS.txt1 confuso incusu logado musexc musicas musinc muslist
Changed:
<
<
O sea, el Shell vió el asterisco (*), lo expandió con el nombre de todos los archivos del directório y el comando echo los mostró em la pantalla separados por espacios en blanco. Visto esto vamos a ver como resolver el problema que nos propusimos:
>
>
O sea, el Shell vio el asterisco (*), lo expandió con el nombre de todos los archivos del directorio y el comando echo los mostró en la pantalla separados por espacios en blanco. Visto esto vamos a ver como resolver el problema que nos propusimos:
 
$ cat testefor1
Line: 128 to 128
 ArchDoDOS.txt1:confuso:incusu:logado:musexc:musicas:musinc:muslist:$
Changed:
<
<
Como viste, el Shell transformó el asterisco (que odea ser llamado de asterístico) en una lista de archivos separados por espacios en blanco. cuando el for vió aquella lista, él dijo: "Opa!, lista separadas por espacios es mi especialidad!"
>
>
Como viste, el Shell transformó el asterisco (es odioso ser llamado por un asterisco) en una lista de archivos separados por espacios en blanco. cuando el for vio aquella lista, se dijo: "Opa!, lista separadas por espacios es mi especialidad!"
 
Changed:
<
<
El bloque de comandos a ser ejecutado era solamente el echo, que con la opción -n listó la variable $Arch seguida de dos puntos (:), sin saltar la línea. El signo de ($) del final de la línea de ejecución es el prompt. que permaneció en la misma línea tambiém en función de la opción -n.
>
>
El bloque de comandos para ejecutar era solamente el echo, que con la opción -n listó la variable $Arch seguida de dos puntos (:), sin saltar de línea. El signo de ($) del final de la línea de ejecución es el prompt. que permaneció en la misma línea también en función de la opción -n.
 Otro ejemplo simple (por ahora):

Line: 155 to 155
  Como viste, este ejemplo es tan bobo y simple como el anterior, pero sirve para mostrar el comportamiento básico del for.
Changed:
<
<
Vea la fuerza del for: todavia estamos en la primera sintáxis del comando y ya estoy mostrando nuevas formas de usarlo. Allá atrás, te habia hablado que el for usaba listas separadas por espacios en blanco, pero eso es una verdad a medias, era sólo para facilitar la compresión.
>
>
Fíjate en la fuerza del for: todavía estamos en la primera sintaxis del comando y ya estoy mostrando nuevas formas de usarlo. Allá atrás, te había hablado que el for usaba listas separadas por espacios en blanco, pero eso es una verdad a medias, era sólo para facilitar la compresión.
 
Changed:
<
<
En realidad, las listas no son obligatoriamente separadas por espacios pero antes de seguir, dejame mostrarte como se comporta una variable del sistema llamada de $IFS. Nota su contenido:
>
>
En realidad, las listas no son obligatoriamente separadas por espacios, pero antes de seguir, déjame mostrarte como se comporta una variable del sistema llamada $IFS. Observa su contenido:
 
$ echo "$IFS" | od -h
Line: 190 to 190
 En el comando cat, la opción -e representa el <ENTER> como un signo de pesos ($) y la opción -t representa el <TAB> como un ^I. Usé los dos puntos (:) para mostrar el inicio y el fin del echo. y de esta forma, otra vez podemos notar que los tres caracteres están presentes en aquella variable.
Changed:
<
<
Ahora, IFS significa Inter Field Separator o, traduciendo, separador entre campos. Una vez entendido eso, puedo afirmar (porque lo voy a probar) que el comando for no usa listas separadas por espacios en blanco, sino por el contnido de la variable $IFS, cuyo valor padrón (default) son esos caracteres que acabamos de ver. Para comprobarlo, vamos a mostrar un script que recibe el nombre del artista como parámetro y lista las músicas que él ejecuta, pero primero veremos como está nuestro archivo musicas:
>
>
Ahora, IFS significa Inter Field Separator o, traduciendo, separador entre campos. Una vez entendido eso, puedo afirmar (porque lo voy a probar) que el comando for no usa listas separadas por espacios en blanco, sino por el contenido de la variable $IFS, cuyo valor por defecto (default) son esos caracteres que acabamos de ver. Para comprobarlo, vamos a mostrar un script que recibe el nombre del artista como parámetro y lista las músicas que este ejecuta, pero primero veremos como está nuestro archivo musicas:
 
$ cat musicas
Line: 223 to 223
 done
Changed:
<
<
El script, como siempre, comienza testando si los parámetros fueron pasados correctamente, en seguida el IFS fue configurado para <ENTER> y dos puntos (:) (como demuentran las comillas en líneas diferentes), porque es él el que separa los bloques Artistan~Musicam. De esta forma, la varible $ArtMus irá a recibir cada uno de estos bloques del archivo (note que el for ya recibe los registros sin el álbum en virtud del cut en su línea). En el caso de que encuentre el parámetro ($1) en el bloque, el segundo cut listará solamente el nombre de la música. Vamos a ejecutarlo:
>
>
El script, como siempre, comienza testando si los parámetros fueron pasados correctamente, en seguida el IFS fue configurado para <ENTER> y dos puntos (:) (como demuestran las comillas en líneas diferentes), porque es él el que separa los bloques Artistan~Musicam. De esta forma, la variable $ArtMus irá a recibir cada uno de estos bloques del archivo (observa que el for ya recibe los registros sin el álbum en virtud del cut en su línea). En el caso de que encuentre el parámetro ($1) en el bloque, el segundo cut listará solamente el nombre de la música. Vamos a ejecutarlo:
 
$ listartista Artista1
Line: 235 to 235
 Musica10
Changed:
<
<
Epa! Pasaron dos cosas no deseadas: los bloques también fueron listados y la Musica10 idem. Además de eso, nuestro archivo de músicas está muy simple, en la vida real, tanto la música quanto el artista tienen más de un nombre. Suponga que el artista fuera una dupla de música folclórica llamada Clitandro & Eduviges (no gusto ni de dar la idea, con temor que se haga realidad smile ). En este caso el $1 sería Clitandro y el resto de este lindo nombre sería ignorado en la búsqueda.
>
>
Epa! Pasaron dos cosas no deseadas: los bloques también fueron listados y la Musica10 también. Además de eso, nuestro archivo de músicas es muy simple, en la vida real, tanto la música como el artista tienen más de un nombre. Suponte que el artista fuera una dupla de música folclórica llamada Clitandro & Eduviges (no me atrevo ni a dar la idea, por miedo a que se haga realidad smile ). En este caso el $1 sería Clitandro y el resto de este lindo nombre sería ignorado en la búsqueda.
 
Changed:
<
<
Para que eso no ocurriese, deberia pasar el nombre del artista entre comillas (") o alterar $1 por $@ (que significa todos los parámetros pasados), que es la mejor solución, pero en este caso tendría que modificar la crítica de los parámetros y el grep. La nueva crítica no actuaria si yo pasase un parâmetro, o por lo menos un parámetro y en cuanto al grep, vea lo que resultaria después de la substitución del $* (que entraría en lugar del $1) por los parámetros:
>
>
Para que eso no ocurriese, debería pasar el nombre del artista entre comillas (") o alterar $1 por $@ (que significa todos los parámetros pasados), que es la mejor solución, pero en este caso tendría que modificar la crítica de los parámetros y el grep. La nueva crítica no actuaria si yo pasase un parámetro, o por lo menos un parámetro y en cuanto al grep, mira lo que resultaría después de la substitución del $* (que entraría en lugar del $1) por los parámetros:
 
    echo "$ArtMus" | grep clitandro & eduviges
Line: 249 to 249
  echo "$ArtMus" | grep -i "clitandro & eduviges"
Changed:
<
<
Donde fue colocada la opción -i para que la búsqueda ignorase mayúsculas y minúsculas y las comillas también fueron insertadas para que el nombre del artista fuera visto como una cadena única e monolítica.
>
>
Donde fue colocada la opción -i para que la búsqueda ignorase mayúsculas y minúsculas y las comillas también fueron insertadas para que el nombre del artista fuera visto como una cadena única y monolítica.
 
Changed:
<
<
Todavia falta arreglar el error de haber listado el Artista10. Para esto, lo mejor es decirle al grep que la cadena está en el início ( forma cuya expresión regular es ^) de $ArtMus y luego después viene un til (~). Es necesario también que se redireccione la salida del grep para /dev/null para que los bloques no sean listados más . Vea entonces la nueva (y definitiva) cara del programa:
>
>
Todavia falta arreglar el error de haber listado al Artista10. Para esto, lo mejor es decirle al grep que la cadena está en el início ( forma cuya expresión regular es ^) de $ArtMus y luego después viene una tilde (~). Es necesario también que se redireccione la salida del grep para /dev/null para que los bloques no sean listados más . Observa entonces la nueva (y definitiva) cara del programa:
 
$ cat listartista
Line: 299 to 299
       - Eso mismo, no? Esta construcción a primera vista parece extraña pero es bastante simple. En este caso, var asumirá uno a uno cada uno de los parámetros pasados para el progama.
Changed:
<
<
Vamos rapidito a los ejemplos para entender mejor. Vamos a hacer un script que reciba como parámetro una cantidad de músicas y liste sus autores:
>
>
Vamos rapidito a los ejemplos para entenderlo mejor. Vamos a hacer un script que reciba como parámetro una cantidad de músicas y liste sus autores:
 
$ cat listamusica
Line: 331 to 331
 done
Changed:
<
<
De la misma forma que los otros, comenzamos el ejercício con una crítica sobre los parámetros recibidos, en seguida hicimos un for en que la varible $Musica recibirá cada uno de los parámetros pasados, colocando en $Str todos los álbuns que contienen las músicas pasadas. En seguida, el otro for agarra cada bloque Artista~Musica en los registros que están en $Str y lista cada artista que ejecute aquella música.
>
>
De la misma forma que los otros, comenzamos el ejercício con una crítica sobre los parámetros recibidos, en seguida hicimos un for en que la varible $Musica recibirá cada uno de los parámetros pasados, colocando en $Str todos los álbums que contienen las músicas pasadas. En seguida, el otro for coge cada bloque Artista~Musica de los registros que están en $Str y lista cada artista que ejecute aquella música.
  Como siempre vamos a ejecutarlo para ver si realmente funciona:
Line: 346 to 346
  No encontrada
Changed:
<
<
La lista quedó fea porque todavia no sabemos dar formato a la salida, pero cualquier día de estos, cuando sepas posicionar el cursor, hacer negrito, trabajar con colores y etc, haremos esta lista nuevamente usando todas estas perfumerías y entoces quedará bien coqueto.
>
>
La lista quedó fea porque todavia no sabemos dar formato a la salida, pero cualquier día de estos, cuando sepas posicionar el cursor, hacer negritas, trabajar con colores, etc, haremos esta lista nuevamente usando todas estas perfumerías y entoces quedará bien coqueto.
  A esta altura de los acontecimientos debes estar preguntandote: "Y aquél for tradicional de los otros lenguajes en que sale contando a partir de un número, con un determinado incremento hasta alcanzar una condición?"
Changed:
<
<
Y es ahí que te respondo: "Yo no te dije que nuestro for es más completo que los otros?" Para hacer eso existen dos formas:
>
>
Y es ahí donde te respondo: "Yo no te dije que nuestro for es más completo que los otros?" Para hacer eso existen dos formas:
 
Changed:
<
<
1 - con la primera sintáxis que vimos, como en los exemplos a seguir directo en el prompt:
>
>
1 - con la primera sintáxis que vimos, como en los siguientes ejemplos directamente en el prompt:
 
$ for i in $(seq 9)
Line: 362 to 362
 1 2 3 4 5 6 7 8 9
Changed:
<
<
Aquí, la variable i asumió los enteros del 1 al 9 generados por el comando seq y la opción -n del echo fue usada para no saltar la línea a cada número listado (me siento ecologicamente correcto por no gastar una cantidad de papel de la revista cuando eso puede ser evitado). Además usando el for con seq:
>
>
Aquí, la variable i asumió los enteros del 1 al 9 generados por el comando seq y la opción -n del echo fue usada para no saltar de línea con cada número listado (me siento ecologicamente correcto por no gastar una cantidad de papel de la revista cuando eso puede ser evitado). Además usando el for con seq:
 
$ for i in $(seq 3 9)
Line: 382 to 382
 0 3 6 9
Changed:
<
<
2 – La otra forma de hacer lo deseado es con una sintáxis muy parecida al for del lenguaje C, como veremos a seguir.
>
>
2 – La otra forma de hacer lo deseado es con una sintáxis muy parecida al for del lenguaje C, como veremos a continuación.
 

Tercera sintáxis del comando for:

Line: 403 to 403
 cond    - Significa que el loop o lazo del for será ejecutado en cuanto la var no cumpla la condición cond;
incr    - Significa el incremento que la variable var sufrirá en cada pasada del loop.
Changed:
<
<
Como siempre vamos a los ejemplos que la cosa queda más fácil:
>
>
Como siempre vamos a los ejemplos y la cosa quedara más fácil:
 
$ for ((i=1; i<=9; i++))
Line: 413 to 413
 1 2 3 4 5 6 7 8 9
Changed:
<
<
En este caso la variable i partió del valor inicial 1, el bloque de comando (aqui solamente el echo) será ejecutado em cuanto i sea menor o igual (<=) a 9 y el incremento de i será de 1 a cada pasada del loop.
>
>
En este caso la variable i partió del valor inicial 1, el bloque de comando (aqui solamente el echo) será ejecutado en cuanto i sea menor o igual (<=) a 9 y el incremento de i será de 1 a cada pasada del loop.
 
Changed:
<
<
Note que en el for propiamente dicho (y no en el bloque de comandos) no coloqué un signo de pesos ($) antes del i, y la notación para incrementar (i++) es diferente de la que vimos hasta ahora. Esto es porque el uso de paréntesis dobles (así como el comando let) llama el interpretador aritmético del Shell, que es más tolerante.
>
>
Fíjate que en el for propiamente dicho (y no en el bloque de comandos) no coloqué un signo de pesos ($) antes del i, y la notación para incrementar (i++) es diferente de la que vimos hasta ahora. Esto es porque el uso de paréntesis dobles (así como el comando let) llama el interpretador aritmético del Shell, que es más tolerante.
 
Changed:
<
<
Como me referí al comando let, sólo para mostrar como funciona y la versatilidad del for, vamos hacer la misma cosa, omitindo sin embargo, la última parte del for, pasándola para el bloque de comandos.
>
>
Como me referí al comando let, y sólo para mostrar como funciona, vamos hacer lo mismo, omitiendo sin embargo, la última parte del for, pasándola hacia el bloque de comandos, así ademas veras la versatilidad del for.
 
$ for ((; i<=9;))
Line: 428 to 428
 1 2 3 4 5 6 7 8 9
Changed:
<
<
Ve que el incremento salió del cuerpo del for y pasó para el bloque de comandos, nota también que cuando usé el let, no fue necesario siquiera inicializar la varible $i. Ve los comandos a seguir dados directamente en el_prompt_ para mostrar lo que acabo de hablar:
>
>
Observa que el incremento desapareció del cuerpo del for y pasó dentro del bloque de comandos, fíjate también que cuando usé el let, no fue necesario siquiera inicializar la varible $i. Observa los siguientes comandos escritos directamente en el_prompt_ para mostrar lo que acabo de decir:
 
$ echo $j
Line: 440 to 440
  O sea, la variable $j ni siquiera existía y en el primero let asumió el valor 0 (cero) para, después del incremento, tener el valor 1.
Changed:
<
<
Ve como las cosas quedan simples:
>
>
Fíjate en lo simples que son las cosas:
 
$ for arq in *
Line: 462 to 462
 12 -> testefor2
Changed:
<
<
     - Y ahí amigo!, tengo la seguridad que hoy tomaste un jarabe del comando for. Por hoy es suficiente, la próxima vez que nos encontremos hablaremos sobre otras instruciones de loop, pero me gustaria que hasta allá, hicieses un pequeño script para contar la cantidad de palabras de un archivo texto, cuyo nombre sería recibido por parámetro.
>
>
     - Y hasta aqui amigo!, tengo la seguridad que hoy tomaste una buena dosis de jarabe del comando for. Por hoy es suficiente, la próxima vez que nos encontremos hablaremos sobre otras instruciones de loop, pero me gustaria que hasta entonces, hicieses un pequeño script para contar la cantidad de palabras de un archivo texto, cuyo nombre sería recibido por parámetro.
 
Changed:
<
<
OBS: Esa cuenta tiene que ser hecha usando el comando for para que te habitues al uso. No vale usar o wc -w.
>
>
OBS: Esa cuenta tiene que ser hecha usando el comando for para que te habitues a su uso. No vale usar o wc -w.
       - Chico! Tráeme, por favor la del estribo!
Changed:
<
<
Y no te olvides, cualquer duda o falta de compañia para tomar un chopp o hasta para hablar mal de los políticos lo único que tienes que hacer es mandarme un e-mail para julio.neves@gmail.com. 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.
>
>
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 julio.neves@gmail.com. Voy aprovechar también 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

Revision 403 Feb 2008 - JulioNeves

Line: 1 to 1
Changed:
<
<

Conversa de bar Parte V

>
>

Conversación de bar Parte V

 

Revision 313 Feb 2007 - JulioNeves

Line: 1 to 1
 

Conversa de bar Parte V

Line: 470 to 470
  Y no te olvides, cualquer duda o falta de compañia para tomar un chopp o hasta para hablar mal de los políticos lo único que tienes que hacer es mandarme un e-mail para julio.neves@gmail.com. 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 - 20 Oct 2006

Revision 230 Oct 2006 - Main.HumbertoPina

Line: 1 to 1
Changed:
<
<

En construcción Conversa de bar Parte V

>
>

Conversa de bar Parte V

 
Line: 48 to 48
       - Ahhh! Descubri que el número después del exit dará el código de retorno del programa (o $?, te acuerdas?), y de esta forma, como fue todo bien ejecutado, se cerraría con el $? = 0. Sin embargo, si observas, verás que en el caso de que el programa no haya recibido el nombre del archivo o en el caso de que el operador no tuviera privilégios de grabación sobre este arquivo, el código de retorno ($?) sería diferente do cero.
Changed:
<
<
     - Grande!, aprendiste bien, pero es bueno dejar claro que el exit 0, simplemente exit, o no colocar exit, producen igualmente un código de retorno ($?) igual a cero. Ahora vamos a hablar sobre las instrucciones de loop o lazo, pero antes voy a pasar el concepto de bloque de programa.
>
>
     - Grande!, aprendiste bien, pero es bueno dejar claro que el exit 0, simplemente exit, o no colocar exit, producen igualmente un código de retorno ($?) igual a cero, si el programa fue bien ejecutado. Ahora vamos a hablar sobre las instrucciones de loop o lazo, pero antes voy a pasar el concepto de bloque de programa.
  Hasta ahora ya vimos algunos bloques de programa, como cuando te mostré un ejemplo para hacer un cd para adentro de un directório, el que era así:
Line: 74 to 74
 

El comando for

Changed:
<
<
Se ya estás habituado a programar, con seguridad conoces el comando for, pero lo que no sabes es que el for, que és una instrucción intrínseca del Shell (esto significa que el código fuente del comando es parte del código fuente del Shell, o sea en buen idioma programés es un built-in), es mucho más poderoso que los semejantes de otras lenguajes.
>
>
Si ya estás habituado a programar, con seguridad conoces el comando for, pero lo que no sabes es que el for, que es una instrucción intrínseca del Shell (esto significa que el código fuente del comando es parte del código fuente del Shell, o sea en buen idioma programés es un built-in), es mucho más poderoso que los semejantes de otras lenguajes.
  Vamos a entender su sintáxis, primero en español y después como funciona realmente.
Line: 235 to 235
 Musica10
Changed:
<
<
Epa! Pasaron dos cosas no deseadas: los bloques también fueron listados y la Musica10 idem. Además de eso, nuestro archivo de músicas está muy simple, en la vida real, tanto la música quanto el artista tienen más de un nombre. Suponga que el artista fuera una dupla de música folclórica llamada Clitandro & Eduviges (no gusto ni de dar la idea con temor que se haga realidad:). En este caso el $1 sería Clitandro y el resto de este lindo nombre sería ignorado en la búsqueda.
>
>
Epa! Pasaron dos cosas no deseadas: los bloques también fueron listados y la Musica10 idem. Además de eso, nuestro archivo de músicas está muy simple, en la vida real, tanto la música quanto el artista tienen más de un nombre. Suponga que el artista fuera una dupla de música folclórica llamada Clitandro & Eduviges (no gusto ni de dar la idea, con temor que se haga realidad smile ). En este caso el $1 sería Clitandro y el resto de este lindo nombre sería ignorado en la búsqueda.
 
Changed:
<
<
Para que eso no ocurriese, deberia pasar el nombre del artista entre comillas (") o alterar $1 por $@ (que significa todos los parámetros pasados), que es la mejor solución, pero en este caso tendría que modificar la crítica de los parámetros y el grep. La nueva crítica no actuaria si yo pasase un parâmetro, o por lo menos un parámetro y en cuanto al grep, vea lo que resultaria después de la substituición del $* (que entraría en lugar del $1) por los parámetros:
>
>
Para que eso no ocurriese, deberia pasar el nombre del artista entre comillas (") o alterar $1 por $@ (que significa todos los parámetros pasados), que es la mejor solución, pero en este caso tendría que modificar la crítica de los parámetros y el grep. La nueva crítica no actuaria si yo pasase un parâmetro, o por lo menos un parámetro y en cuanto al grep, vea lo que resultaria después de la substitución del $* (que entraría en lugar del $1) por los parámetros:
 
    echo "$ArtMus" | grep clitandro & eduviges
Line: 249 to 249
  echo "$ArtMus" | grep -i "clitandro & eduviges"
Changed:
<
<
Donde fue colocada la opción -i para que la búsqueda ignorase mayúsculas y minúsculas y las comillas también fueron insertadas para que el nombre del artista fuera visto como una cadena sola e monolítica.
>
>
Donde fue colocada la opción -i para que la búsqueda ignorase mayúsculas y minúsculas y las comillas también fueron insertadas para que el nombre del artista fuera visto como una cadena única e monolítica.
 
Changed:
<
<
Todavia falta arreglar el error de haber listado el Artista10. Para esto lo mejor es decir al grep que la cadena está en el início (cuya expresión regular es ^) de $ArtMus y luego después viene un til (~). Es necesario también que se redireccione la salida del grep para /dev/null para que los bloques no sean más listados. Vea entonces la nueva (y definitiva) cara del programa:
>
>
Todavia falta arreglar el error de haber listado el Artista10. Para esto, lo mejor es decirle al grep que la cadena está en el início ( forma cuya expresión regular es ^) de $ArtMus y luego después viene un til (~). Es necesario también que se redireccione la salida del grep para /dev/null para que los bloques no sean listados más . Vea entonces la nueva (y definitiva) cara del programa:
 
$ cat listartista
Line: 346 to 346
  No encontrada
Changed:
<
<
La lista quedó fea porque todavia no sabemos dar formato a la salida, pero cualquier día de estos, cuando sepas posicionar el cursor, hacer negrito, trabajar con colores y etc, haremos esta lista nuevamente usando todas estas perfumerías y entoces quedará muy fashion.
>
>
La lista quedó fea porque todavia no sabemos dar formato a la salida, pero cualquier día de estos, cuando sepas posicionar el cursor, hacer negrito, trabajar con colores y etc, haremos esta lista nuevamente usando todas estas perfumerías y entoces quedará bien coqueto.
 
Changed:
<
<
A esta altura de los acontecimientos debes estar preguntandote: "Y aquél for tradicional d los otros lenguajes en que sale contando a partir de un número, con un determinado incremento hasta alcanzar una condición?"
>
>
A esta altura de los acontecimientos debes estar preguntandote: "Y aquél for tradicional de los otros lenguajes en que sale contando a partir de un número, con un determinado incremento hasta alcanzar una condición?"
  Y es ahí que te respondo: "Yo no te dije que nuestro for es más completo que los otros?" Para hacer eso existen dos formas:
Line: 466 to 466
  OBS: Esa cuenta tiene que ser hecha usando el comando for para que te habitues al uso. No vale usar o wc -w.
Changed:
<
<
     - Ahí Chico! Tráeme la del estribo!
>
>
     - Chico! Tráeme, por favor la del estribo!
  Y no te olvides, cualquer duda o falta de compañia para tomar un chopp o hasta para hablar mal de los políticos lo único que tienes que hacer es mandarme un e-mail para julio.neves@gmail.com. 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 120 Oct 2006 - Main.HumbertoPina

Line: 1 to 1
Added:
>
>

En construcción Conversa de bar Parte V

     - Y ahí amigo! Ordenó sus ideas? Su cabeza ya se fundió, o todavia aguanta más Shell?

     - Aguanto, claro! Estoy gustando mucho! Me gustó tanto que hasta me esmeré en el ejercício que me dejó. Te acuerdas que me pediste para hacer un programa que recebiría como parámetro el nombre de un archivo y que quando ejecutado salvaría este archivo con el nombre original seguido de un til (~) y colocaría este archivo dentro do vi?

     - Claro que me acuerdo, muéstrame y explica como lo hiciste.

$ cat vira #!/bin/bash # # vira - vi grabando el archivo anterior # == = =

# Verificando si fue pasado 1 parámetro if [ "$#" -ne 1 ] then echo "Erro -> Uso: $0 " exit 1 fi

Arq=$1 # En caso de que el archivo no exista, no hay copia para grabar if [ ! -f "$Arq" ] then vi $Arq exit 0 fi

# Si no puedo alterar el archivo, para que voy a usar el vi? if [ ! -w "$Arq" ] then echo "Usted no tiene privilegios de grabación en $Arq" exit 2 fi

# Ya que está todo OK, voy a salvar la copia y llamar el vi cp -f $Arq $Arq~ vi $Arq exit 0

     - Bárbaro, muy bien! Pero dime una cosa: porque terminaste el programa con un exit 0?

     - Ahhh! Descubri que el número después del exit dará el código de retorno del programa (o $?, te acuerdas?), y de esta forma, como fue todo bien ejecutado, se cerraría con el $? = 0. Sin embargo, si observas, verás que en el caso de que el programa no haya recibido el nombre del archivo o en el caso de que el operador no tuviera privilégios de grabación sobre este arquivo, el código de retorno ($?) sería diferente do cero.

     - Grande!, aprendiste bien, pero es bueno dejar claro que el exit 0, simplemente exit, o no colocar exit, producen igualmente un código de retorno ($?) igual a cero. Ahora vamos a hablar sobre las instrucciones de loop o lazo, pero antes voy a pasar el concepto de bloque de programa.

Hasta ahora ya vimos algunos bloques de programa, como cuando te mostré un ejemplo para hacer un cd para adentro de un directório, el que era así:

cd lmb 2> /dev/null ||
    {
    mkdir lmb
    cd lmb
    }

El fragmento contenido entre las dos llaves ({}), forman un bloque de comandos. También en este ejercício que acabamos de ver, en que salvamos el archivo antes de editarlo, existen varios bloque de comandos comprendidos entre los then y los fi del if.

Un bloque de comandos también puede estar dentro de un case, o entre un do y un done.

     - Espera ahí Julio, que do y done son esos, no me acuerdo de que hayas hablado de ellos y mira que estoy prestando mucha atención...

     - Claro, todavia no habia hablado porque no habia llegado el momento adecuado. Todas las instrucciones de loop o lazo, ejecutan los comandos del bloque comprendido entre el do y el done.

Comandos de Loop (o lazo)

Las instruciones de loop o lazo son el for, el while y el until que pasaré a explicarte una a una a partir de hoy.

El comando for

Se ya estás habituado a programar, con seguridad conoces el comando for, pero lo que no sabes es que el for, que és una instrucción intrínseca del Shell (esto significa que el código fuente del comando es parte del código fuente del Shell, o sea en buen idioma programés es un built-in), es mucho más poderoso que los semejantes de otras lenguajes.

Vamos a entender su sintáxis, primero en español y después como funciona realmente.

    para var en val1 val2 ... valn
    haga
        cmd1
        cmd2
        cmdn
    hecho

Donde la variable var asume cada uno de los valores de la lista val1 val2 ... valn y para cada uno de eses valores ejecuta el bloque de comandos formado por cmd1, cmd2 y cmdn

Ahora que ya vimos el significado de la instrucción en español, veamos la sintáxis correcta:

Primera sintáxis del comando for:

    for var in val1 val2 ... valn
    do
        cmd1
        cmd2
        cmdn
    done

Vamos directo para los ejemplos, a fin de entender el funcionamento de este comando. Vamos a escribir un script para listar todos los archivos de nuestro directório separados por dos puntos, pero vea primero:

$ echo * ArchDoDOS.txt1 confuso incusu logado musexc musicas musinc muslist

O sea, el Shell vió el asterisco (*), lo expandió con el nombre de todos los archivos del directório y el comando echo los mostró em la pantalla separados por espacios en blanco. Visto esto vamos a ver como resolver el problema que nos propusimos:

$ cat testefor1 #!/bin/bash # 1o. Prog didáctico para entender el for

for Arch in * do echo -n $Arq: # La opción -n es para no saltar la línea done

Ahora vamos a ejecutarlo:

$ testefor1 ArchDoDOS.txt1:confuso:incusu:logado:musexc:musicas:musinc:muslist:$

Como viste, el Shell transformó el asterisco (que odea ser llamado de asterístico) en una lista de archivos separados por espacios en blanco. cuando el for vió aquella lista, él dijo: "Opa!, lista separadas por espacios es mi especialidad!"

El bloque de comandos a ser ejecutado era solamente el echo, que con la opción -n listó la variable $Arch seguida de dos puntos (:), sin saltar la línea. El signo de ($) del final de la línea de ejecución es el prompt. que permaneció en la misma línea tambiém en función de la opción -n. Otro ejemplo simple (por ahora):

$ cat testefor2 #!/bin/bash # 2o. Prog didáctico para entender el for

for Palabra in Conversa de Bar do echo $Palabra done

Y ejecutando resulta:

$ testefor2 Conversa de Bar

Como viste, este ejemplo es tan bobo y simple como el anterior, pero sirve para mostrar el comportamiento básico del for.

Vea la fuerza del for: todavia estamos en la primera sintáxis del comando y ya estoy mostrando nuevas formas de usarlo. Allá atrás, te habia hablado que el for usaba listas separadas por espacios en blanco, pero eso es una verdad a medias, era sólo para facilitar la compresión.

En realidad, las listas no son obligatoriamente separadas por espacios pero antes de seguir, dejame mostrarte como se comporta una variable del sistema llamada de $IFS. Nota su contenido:

$ echo "$IFS" | od -h 0000000 0920 0a0a 0000004

O sea, mandé la variable (protegida de la interpretación del Shell por las comillas) para un dump hexadecimal (od -h) y resultó:

Contenido de la Variable $IFS
0a <ENTER>
  Hexadecimal     Significado  
09 <TAB>
20 <ESPACIO>

Donde el último 0a fue originado por el <ENTER> dado al final del comando. Para mejorar la explicación, vamos a ver eso de otra forma:

$ echo ":$IFS:" | cat -vet : ^I$ :$

Presta atención a lo siguiente para entender la construcción del comando cat:

Pinguim com placa de dica En el comando cat, la opción -e representa el <ENTER> como un signo de pesos ($) y la opción -t representa el <TAB> como un ^I. Usé los dos puntos (:) para mostrar el inicio y el fin del echo. y de esta forma, otra vez podemos notar que los tres caracteres están presentes en aquella variable.

Ahora, IFS significa Inter Field Separator o, traduciendo, separador entre campos. Una vez entendido eso, puedo afirmar (porque lo voy a probar) que el comando for no usa listas separadas por espacios en blanco, sino por el contnido de la variable $IFS, cuyo valor padrón (default) son esos caracteres que acabamos de ver. Para comprobarlo, vamos a mostrar un script que recibe el nombre del artista como parámetro y lista las músicas que él ejecuta, pero primero veremos como está nuestro archivo musicas:

$ cat musicas album 1^Artista1~Musica1:Artista2~Musica2 album 2^Artista3~Musica3:Artista4~Musica4 album 3^Artista5~Musica5:Artista6~Musica6 album 4^Artista7~Musica7:Artista1~Musica3 album 5^Artista9~Musica9:Artista10~Musica10

En base a este esquema mostrado arriba fue desarrollado el script que sigue:

$ cat listartista #!/bin/bash # Dado un artista, muestra sus músicas

if [ $# -ne 1 ] then echo Usted debería haber pasado un parámetro exit 1 fi

IFS=" :"

for ArtMus in $(cut -f2 -d^ musicas) do echo "$ArtMus" | grep $1 && echo $ArtMus | cut -f2 -d~ done

El script, como siempre, comienza testando si los parámetros fueron pasados correctamente, en seguida el IFS fue configurado para <ENTER> y dos puntos (:) (como demuentran las comillas en líneas diferentes), porque es él el que separa los bloques Artistan~Musicam. De esta forma, la varible $ArtMus irá a recibir cada uno de estos bloques del archivo (note que el for ya recibe los registros sin el álbum en virtud del cut en su línea). En el caso de que encuentre el parámetro ($1) en el bloque, el segundo cut listará solamente el nombre de la música. Vamos a ejecutarlo:

$ listartista Artista1 Artista1~Musica1 Musica1 Artista1~Musica3 Musica3 Artista10~Musica10 Musica10

Epa! Pasaron dos cosas no deseadas: los bloques también fueron listados y la Musica10 idem. Además de eso, nuestro archivo de músicas está muy simple, en la vida real, tanto la música quanto el artista tienen más de un nombre. Suponga que el artista fuera una dupla de música folclórica llamada Clitandro & Eduviges (no gusto ni de dar la idea con temor que se haga realidad:). En este caso el $1 sería Clitandro y el resto de este lindo nombre sería ignorado en la búsqueda.

Para que eso no ocurriese, deberia pasar el nombre del artista entre comillas (") o alterar $1 por $@ (que significa todos los parámetros pasados), que es la mejor solución, pero en este caso tendría que modificar la crítica de los parámetros y el grep. La nueva crítica no actuaria si yo pasase un parâmetro, o por lo menos un parámetro y en cuanto al grep, vea lo que resultaria después de la substituición del $* (que entraría en lugar del $1) por los parámetros:

    echo "$ArtMus" | grep clitandro & eduviges

Lo que resultaría en un error. Lo corretco sería:

    echo "$ArtMus" | grep -i "clitandro & eduviges"

Donde fue colocada la opción -i para que la búsqueda ignorase mayúsculas y minúsculas y las comillas también fueron insertadas para que el nombre del artista fuera visto como una cadena sola e monolítica.

Todavia falta arreglar el error de haber listado el Artista10. Para esto lo mejor es decir al grep que la cadena está en el início (cuya expresión regular es ^) de $ArtMus y luego después viene un til (~). Es necesario también que se redireccione la salida del grep para /dev/null para que los bloques no sean más listados. Vea entonces la nueva (y definitiva) cara del programa:

$ cat listartista #!/bin/bash # Dado un artista, muestra sus músicas # versao 2

if [ $# -eq 0 ] then echo Usted debería haber pasado un parámetro exit 1 fi

IFS=" :"

for ArtMus in $(cut -f2 -d^ musicas) do echo "$ArtMus" | grep -i "^$@~" > /dev/null && echo $ArtMus | cut -f2 -d~ done

Que ejecutado da:

$ listartista Artista1 Musica1 Musica3

Segunda sintáxis del comando for:

    for var
    do
        cmd1
        cmd2
        cmdn
    done

     - Espera ahí!, sin el in como va a saber que valor asumir?

     - Eso mismo, no? Esta construcción a primera vista parece extraña pero es bastante simple. En este caso, var asumirá uno a uno cada uno de los parámetros pasados para el progama.

Vamos rapidito a los ejemplos para entender mejor. Vamos a hacer un script que reciba como parámetro una cantidad de músicas y liste sus autores:

$ cat listamusica #!/bin/bash # Recibe parte de los nombres de músicas como parámetro y # lista los intérpretes. Si el nombre es compuesto, debe # ser pasado entre comillas. # ex. "No soy tu perrito, no!" "Asadito de Madre" # if [ $# -eq 0 ] then echo Uso: $0 musica1 [musica2] ... [musican] exit 1 fi IFS=" :" for Musica do echo $Musica Str=$(grep -i "$Musica" musicas) || { echo " No encontrada" continue } for ArtMus in $(echo "$Str" | cut -f2 -d^) do echo " $ArtMus" | grep -i "$Musica" | cut -f1 -d~ done done

De la misma forma que los otros, comenzamos el ejercício con una crítica sobre los parámetros recibidos, en seguida hicimos un for en que la varible $Musica recibirá cada uno de los parámetros pasados, colocando en $Str todos los álbuns que contienen las músicas pasadas. En seguida, el otro for agarra cada bloque Artista~Musica en los registros que están en $Str y lista cada artista que ejecute aquella música.

Como siempre vamos a ejecutarlo para ver si realmente funciona:

$ listamusica musica3 Musica4 "Yegüita Pocotó" musica3 Artista3 Artista1 Musica4 Artista4 Yegüita Pocotó No encontrada

La lista quedó fea porque todavia no sabemos dar formato a la salida, pero cualquier día de estos, cuando sepas posicionar el cursor, hacer negrito, trabajar con colores y etc, haremos esta lista nuevamente usando todas estas perfumerías y entoces quedará muy fashion.

A esta altura de los acontecimientos debes estar preguntandote: "Y aquél for tradicional d los otros lenguajes en que sale contando a partir de un número, con un determinado incremento hasta alcanzar una condición?"

Y es ahí que te respondo: "Yo no te dije que nuestro for es más completo que los otros?" Para hacer eso existen dos formas:

1 - con la primera sintáxis que vimos, como en los exemplos a seguir directo en el prompt:

$ for i in $(seq 9) > do > echo -n "$i " > done 1 2 3 4 5 6 7 8 9

Aquí, la variable i asumió los enteros del 1 al 9 generados por el comando seq y la opción -n del echo fue usada para no saltar la línea a cada número listado (me siento ecologicamente correcto por no gastar una cantidad de papel de la revista cuando eso puede ser evitado). Además usando el for con seq:

$ for i in $(seq 3 9) > do > echo -n "$i " > done 4 5 6 7 8 9

O todavia en la forma más completa del seq:

$ for i in $(seq 0 3 9) > do > echo -n "$i " > done 0 3 6 9

2 – La otra forma de hacer lo deseado es con una sintáxis muy parecida al for del lenguaje C, como veremos a seguir.

Tercera sintáxis del comando for:

    for ((var=ini; cond; incr))
    do
        cmd1
        cmd2
        cmdn
    done

Donde:

var=ini - Significa que la variable var comenzará a partir de un valor inicial ini;
cond    - Significa que el loop o lazo del for será ejecutado en cuanto la var no cumpla la condición cond;
incr    - Significa el incremento que la variable var sufrirá en cada pasada del loop.

Como siempre vamos a los ejemplos que la cosa queda más fácil:

$ for ((i=1; i<=9; i++)) > do > echo -n "$i " > done 1 2 3 4 5 6 7 8 9

En este caso la variable i partió del valor inicial 1, el bloque de comando (aqui solamente el echo) será ejecutado em cuanto i sea menor o igual (<=) a 9 y el incremento de i será de 1 a cada pasada del loop.

Note que en el for propiamente dicho (y no en el bloque de comandos) no coloqué un signo de pesos ($) antes del i, y la notación para incrementar (i++) es diferente de la que vimos hasta ahora. Esto es porque el uso de paréntesis dobles (así como el comando let) llama el interpretador aritmético del Shell, que es más tolerante.

Como me referí al comando let, sólo para mostrar como funciona y la versatilidad del for, vamos hacer la misma cosa, omitindo sin embargo, la última parte del for, pasándola para el bloque de comandos.

$ for ((; i<=9;)) > do > let i++ > echo -n "$i " > done 1 2 3 4 5 6 7 8 9

Ve que el incremento salió del cuerpo del for y pasó para el bloque de comandos, nota también que cuando usé el let, no fue necesario siquiera inicializar la varible $i. Ve los comandos a seguir dados directamente en el_prompt_ para mostrar lo que acabo de hablar:

$ echo $j

$ let j++ $ echo $j 1

O sea, la variable $j ni siquiera existía y en el primero let asumió el valor 0 (cero) para, después del incremento, tener el valor 1.

Ve como las cosas quedan simples:

$ for arq in * > do > let i++ > echo "$i -> $Arq" > done 1 -> ArqDoDOS.txt1 2 -> confuso 3 -> incusu 4 -> listamusica 5 -> listartista 6 -> logado 7 -> musexc 8 -> musicas 9 -> musinc 10 -> muslist 11 -> testefor1 12 -> testefor2

     - Y ahí amigo!, tengo la seguridad que hoy tomaste un jarabe del comando for. Por hoy es suficiente, la próxima vez que nos encontremos hablaremos sobre otras instruciones de loop, pero me gustaria que hasta allá, hicieses un pequeño script para contar la cantidad de palabras de un archivo texto, cuyo nombre sería recibido por parámetro.

OBS: Esa cuenta tiene que ser hecha usando el comando for para que te habitues al uso. No vale usar o wc -w.

     - Ahí Chico! Tráeme la del estribo!

Y no te olvides, cualquer duda o falta de compañia para tomar un chopp o hasta para hablar mal de los políticos lo único que tienes que hacer es mandarme un e-mail para julio.neves@gmail.com. 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 - 20 Oct 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