Difference: TWikiBarConversa003 (1 vs. 8)

Revision 814 Feb 2012 - MarioSilva

Line: 1 to 1
 

Conversación de Bar Parte III
<--pula duas linhas-->

Line: 704 to 704
 

-- HumbertoPina - 04 Oct 2006

Added:
>
>

Revision 703 Feb 2008 - JulioNeves

Line: 1 to 1
Changed:
<
<

Conversa de Bar Parte III
<--pula duas linhas-->

>
>

Conversación de Bar Parte III
<--pula duas linhas-->

 

Revision 629 Jan 2008 - CollonsTorre

Line: 1 to 1
 

Conversa de Bar Parte III
<--pula duas linhas-->

Changed:
<
<
    - Mozo, traiga dos choppes por favor, que hoy voy a tener que hablar mucho.
>
>
    - Mozo, traiga dos "choppes" por favor, que hoy voy a tener que hablar mucho.
 

Trabajando con cadenas

Changed:
<
<
Por el título encima no pienses que te voy a enseñar a ser carcelero! Me estoy referiendo a cadena de caracteres!
>
>
Por el título de arriba no pienses que te voy a enseñar a ser carcelero! Me estoy refiriendo a cadenas de caracteres!
 

El Comando cut (que no es la central única de trabajadores)
<--pula duas linhas-->

Line: 62 to 62
 9875789
Changed:
<
<
Como dá para ver, en realidad existen cuatro sintáxis distintas: en la primera (-c1-5), especifiqué una faja de posiciones, en la segunda (-c-6), especifiqué todas las posiciones hasta una determinada columna, en la tercera (-c4-) de una determinada posición en adelante y en la cuarta (-c1,3,5,7,9), determinadas posiciones. La última (-c-3,5,8-) fue solamente para mostrar que podemos mesclar todo.
>
>
Como se puede ver, en realidad existen cuatro sintaxis distintas: en la primera (-c1-5), especifiqué una franja de posiciones, en la segunda (-c-6), especifiqué todas las posiciones hasta una determinada columna, en la tercera (-c4-) de una determinada posición en adelante y en la cuarta (-c1,3,5,7,9), determinadas posiciones. La última (-c-3,5,8-) fue solo para demostrar que lo podemos mezclar todo.
 

El comando cut con la opción -f

Changed:
<
<
Pero no pienses que acabó por ahí! Como debes haber notado, esta forma de cut es útil para archivos con campos de tamaño fijo, sin embargo, actualmente lo que más existe son archivos con campos de tamaño variables, donde cada campo termina con un delimitador. Vamos a dar una ojeada en el archivo musicas que comenzamos a preparar en nuestra conversa de la última vez que estuvimos aqui, en el bar.
>
>
Pero no pienses que acabó por ahí! Como debes haber notado, esta forma de cut es útil para archivos con campos de tamaño fijo, sin embargo, actualmente lo que más existe son archivos con campos de tamaño variables, donde cada campo termina con un delimitador. Vamos a dar una ojeada al archivo musicas que comenzamos a preparar en nuestra conversación de la última vez que estuvimos aquí, en el bar.
 
$ cat musicas
Line: 80 to 80
       nombre del album^intérprete1~nombre de la música1:...:intérpreten~nombre de la músican
Changed:
<
<
O sea, el nombre del álbum será separado por un circunflejo (^) del resto del registro, que está formado por diversos grupos, compuestos por el intérprete de cada música del CD y la respectiva música interpretada. Estos grupos son separados entre sí por dos puntos (:) e internamente, el nombre del intérprete será separado por un til (~), del nombre de la música.
>
>
O sea, el nombre del álbum será separado por un circunflejo (^) del resto del registro, que está formado por diversos grupos, compuestos por el intérprete de cada música del CD y la respectiva música interpretada. Estos grupos son separados entre sí por dos puntos (:) e internamente, el nombre del intérprete será separado por una tilde (~), del nombre de la música.
  Entonces para sacar los datos referentes a todas las segundas músicas del archivo musicas, debemos hacer:
Line: 92 to 92
 Artista8~Musica8
Changed:
<
<
O sea, cortamos el segundo campo (-f de field en inglés), delimitado (-d) por dos puntos (:). En cambio, se quisieramos solamente los intérpretes, podemos hacer:
>
>
O sea, cortamos el segundo campo (-f de field en inglés), delimitado (-d) por dos puntos (:). En cambio, se quisiéramos solamente los intérpretes, podriamos hacer:
 
$ cut -f2 -d: musicas | cut -f1 -d~
Line: 109 to 109
 album 1^Artista1~Musica1:Artista2~Musica2
Changed:
<
<
Ahora observe lo que fue hecho:
>
>
Ahora observa lo que ocurrió:
 
Changed:
<
<
Delimitador del primero cut (:)
>
>
Delimitador del primer cut (:)
       album 1^Artista1~Musica1:Artista2~Musica2
Changed:
<
<
De esta forma, en el primero cut, el primer campo del delimitador (-d) dos puntos (:), es album 1^Artista1~Musica1 y el segundo, que es lo que nos interesa, es Artista2~Musica2.
>
>
De esta forma, en el primer cut, el primer campo del delimitador (-d) dos puntos (:), es album 1^Artista1~Musica1 y el segundo, que es lo que nos interesa, es Artista2~Musica2.
  Vamos ahora a ver lo que pasó con el segundo cut:
Line: 123 to 123
       Artista2~Musica2
Changed:
<
<
Ahora, el primer campo del delimitador (-d) til (~), que es el que nos interesa, é Artista2 y el segundo es Musica2.
>
>
Ahora, el primer campo del delimitador (-d) tilde (~), que es el que nos interesa, es Artista2 y el segundo es Musica2.
 
Changed:
<
<
Si el razonamiento que hicimos para la primera línea fuera aplicado en el resto del archivo, llegariamos a la respuesta anteriormente dada.
>
>
Si el razonamiento que hicimos para la primera línea fuera aplicado al resto del archivo, llegaríamos a la respuesta anteriormente dada.
 

Si hay cut hay paste

Changed:
<
<
Como ya era de esperar, el comando paste sirve para pegar, sólo que aqui en Shell lo que pega son archivos. Para comenzar a entenderlo, vamos a hacer así::
>
>
Como ya era de esperar, el comando paste sirve para pegar, sólo que aquí en Shell lo que pega son archivos. Para empezar a entenderlo, vamos a hacer esto::
 
    paste arch1 arch2
Changed:
<
<
De esta forma el comando mandará para la salida padrón (stdout) cada uno de los registros de arch1, al lado de los registros de arch2 correspondientes y en caso de que ningún delimitador sea especificado, usará por default el <TAB>.
>
>
De esta forma el comando mandará hacia la salida patrón (stdout) cada uno de los registros de arch1, al lado de los registros de arch2 correspondientes y en caso de que no se especifique ningún delimitador, usará por default el <TAB>.
 
Changed:
<
<
El paste es un comando poco usado por su sintáxis ser poco conocida. Vamos a jugar con 2 archivos creados de la siguiente forma:
>
>
El paste es un comando poco usado por que su sintaxis es poco conocida. Vamos a jugar con 2 archivos creados de la siguiente forma:
 
$ seq 10 > enteros
Line: 171 to 171
 

Usando separadores

Changed:
<
<
Como ya fue dicho, el separador default del paste es el <TAB>, pero eso puede ser alterado con la opción -d. Entonces para calcular la suma del contenido de pares primeramente hariamos:
>
>
Como ya fue dicho, el separador default del paste es el <TAB>, pero eso puede ser alterado con la opción -d. Entonces para calcular la suma del contenido de pares primeramente haríamos:
 
Changed:
<
<
$ paste -s -d'+' pares # tambiém podria ser -sd'+'
>
>
$ paste -s -d'+' pares # también podría ser -sd'+'
 2+4+6+8+10
Changed:
<
<
y después pasaríamos esta línea con pipe (|) para la calculadora (bc), que entonces quedaria:
>
>
y después pasaríamos esta línea con pipe (|) hacia la calculadora (bc), y entonces quedaría:
 
$ paste -sd'+' pares | bc
Line: 191 to 191
 $ seq $Num | paste -sd'*' | bc
Changed:
<
<
Con el comando paste tu tambiém puedes montar formatos exóticos como este a seguir:
>
>
Con el comando paste tu también puedes montar formatos exóticos como el siguiente:
 
$ ls | paste -s -d'\t\t\n'
Line: 199 to 199
 arch4 arch5 arch6
Changed:
<
<
Lo que pasó fue lo siguiente: fue especificado para el comando paste que tendria que transformar líneas en columnas (por la opción -s) y que sus separadores (si...! El acepta más de uno, pero solamente uno después de cada columna creada por el comando) serían un <TAB>, otra <TAB> y un <ENTER>, generando de esta forma su salida tabulada en 3 columnas.
>
>
Lo que pasó fue lo siguiente: se le especifico al comando paste que tendría que transformar líneas en columnas (por la opción -s) y que sus separadores (si...! acepta más de uno, pero solamente uno después de cada columna creada por el comando) serían un <TAB>, otro <TAB> y un <ENTER>, generando de esta forma su salida tabulada en 3 columnas.
 
Changed:
<
<
Ahora que ya entendiste esto, ve como hacer la misma cosa, pero de forma más fácil, menos extraña y primitiva, usando el mismo comando pero con la siguiente sintáxis:
>
>
Ahora que ya entendiste esto, observa como hacer lo mismo, pero de forma más fácil, menos extraño y primitivo, usaremos el mismo comando pero con la siguiente sintaxis:
 
$ ls | paste - - -
Line: 209 to 209
 arch4 arch5 arch6
Changed:
<
<
Y esto sucede porque si em vez de especificar los archivos colocamos el signo de menos (-), el comando paste los substituye por la salida o entrada padrón conforme el caso. En el ejemplo anterior los datos fueran mandados para la salida padrón (stdout), porque el pipe (|) estaba desviando la salida del ls para la entrada padrón (stdin) del paste, pero vea el ejemplo a seguir:
>
>
Y esto sucede porque si en lugar de especificar los archivos, colocamos el signo de menos (-), el comando paste los substituye por la salida o entrada patrón conforme al caso. En el ejemplo anterior los datos fueran mandados hacia la salida patrón (stdout), porque el pipe (|) estaba desviando la salida del ls hacia la entrada patrón (stdin) del paste, pero veamos el ejemplo siguiente:
 
$ cat arch1
Line: 226 to 226
 promotor
Changed:
<
<
En este caso, el cut devolvió las tres primeras letras de cada registro de arch1, el paste fue montado para no tener separador (-d"") y recibir la entrada padrón (desviada por el pipe) en el trazo (-), generando la salida junto con arch2.
>
>
En este caso, el cut devolvió las tres primeras letras de cada registro de arch1, el paste fue montado para no tener separador (-d"") y recibir la entrada patrón (desviada por el pipe) en el trazo (-), generando la salida junto con arch2.
 

El Comando tr

Changed:
<
<
Otro comando muy interesante es el tr que sirve para substituir, comprimir o retirar caracteres. Su sintáxis sigue el siguiente padrón:
>
>
Otro comando muy interesante es el tr que sirve para substituir, comprimir o retirar caracteres. Su sintaxis sigue el siguiente patrón:
 
    tr [opciones] cadena1 [cadena2]
Changed:
<
<
El comando tr copia el texto de la entrada padrón (stdin) y cambia, las veces que halle los caracteres de cadena1 por el correspondiente contenido de la cadena2, o cambia las múltiples ocurrencias de los caracteres de cadena1 por solamente un caracter, o todavia puede retirar los caracteres de la cadena1.
>
>
El comando tr copia el texto de la entrada patrón (stdin) y cambia, las veces que encuentre, los caracteres de cadena1 por el correspondiente contenido de la cadena2, o cambia las múltiples coincidencias de los caracteres de cadena1 por solamente un carácter, o todavía puede hacer mas, puede eliminar los caracteres de la cadena1.
  Las principales opciones del comando son:
Line: 244 to 244
 
Principales Opciones del comando tr
  Opción     Significado  
Changed:
<
<
-s   Comprime n ocurrencias de la cadena1 en sólo una  
-d   Retira del archivo los caracteres de la cadena1  
>
>
-s   Comprime n coincidencias de la cadena1 en sólo una  
-d   Elimina del archivo los caracteres de la cadena1  
 

Cambiando caracteres con tr

Line: 257 to 257
 baba
Changed:
<
<
O sea, cambié todas esas ocurrencias de la letra o por la letra a.
>
>
O sea, cambié todas las coincidencias de la letra o por la letra a.
 
Changed:
<
<
Suponga que en un determinado punto de mi script, pido al operador para teclear s o n (si o no), y guardo su respuesta en la variable $Resp. El contenido de $Resp puede estar con letra mayúscula o minúscula, y de esta forma tendria que hacer diversos tests para saber si la respuesta dada fue S, s, N o n. Entonces lo mejor es hacer:
>
>
Suponte que en un determinado punto de mi script, pido al operador que teclee s o n (si o no), y guardo su respuesta en la variable $Resp. El contenido de $Resp puede estar con letras mayúsculas o minúsculas, y de esta forma tendría que hacer diversos tests para saber si la respuesta dada fue S, s, N o n. Entonces lo mejor es hacer:
 
$ Resp=$(echo $Resp | tr SN sn)
Changed:
<
<
y luego de este comando tendria seguridade de que el contenido de $Resp seria un s o un n.
>
>
y despues de ejecutar este comando tendría la seguridad de que el contenido de $Resp seria un s o un n.
  Si mi archivo ArchEnt está todo escrito con letras mayúsculas y deseo pasarlas para minúsculas hago:
Line: 276 to 276
 
Changed:
<
<
Note que em este caso usé la notacióno A-Z para no tener que escribir ABCD...YZ. Otro tipo de notación que puede ser usada son las escape sequences (preferiria escribir en español, pero en este caso como lo traduciría? Secuencias de escape? Medio sin sentido, no te parece? Pero continuemos...) que tambiém son reconocidas por otros comandos y también en lenguaje C, y cuyo significado verás a seguir:
>
>
Observa que en este caso usé la notación A-Z para no tener que escribir ABCD...YZ. Otro tipo de notación que puede ser usada son las escape sequences (preferiría escribir en español, pero en este caso como lo traduciría? Secuencias de escape? Medio sin sentido, no te parece? Pero continuemos...) que también son reconocidas por otros comandos y también en lenguaje C, y cuyo significado verás a continuación:
 
Line: 292 to 292
 

Sacando caracteres con tr

Changed:
<
<
Entonces dejame contarte un "causo": un alumno que estaba enojado conmigo, resolvió complicar mi vida y en un ejercicio práctico, valiendo nota, que pasé para ser hecho en el computador, me entregó el script con todos los comandos separados por punto y coma (recuerdas que te dije que el punto y coma servía para separar diversos comandos en una misma línea?).
>
>
Dejame contarte un "causo": un alumno que estaba enojado conmigo, decidió complicarme la vida y en un ejercicio práctico que pasé para ser hecho en el computador, y que valía para nota, me entregó el script con todos los comandos separados por punto y coma (recuerdas que te dije que el punto y coma servía para separar diversos comandos en una misma línea?).
 
Changed:
<
<
Voy a dar un ejemplo simplificado e idiota de un "chorizo" así:
>
>
Te voy a dar un ejemplo simplificado e idiota de un "chorizo" así:
 
$ cat confuso echo lea Programación Shell Linux de Julio Cezar Neves > libro;cat libro;pwd;ls;rm -f lixo 2>/dev/null;cd ~
Changed:
<
<
Yo ejecutaba el programa y él funcionaba:
>
>
Yo ejecutaba el programa y se ejecutaba así:
 
$ confuso
Line: 310 to 310
 confuso livro musexc musicas musinc muslist numeros
Changed:
<
<
Pero nota de prueba es cosa seria (y billete de dólar es todavia más smile ) entonces, para entender lo que el aluno habia hecho, lo llamé y en su frente ejecuté el siguiente comando:
>
>
Pero nota de prueba es cosa seria (y billete de dólar todavia más smile ) entonces, para entender lo que el alumno habia hecho, lo llamé y delante suyo ejecuté el siguiente comando:
 
$ tr ";" "\n" < confuso
Line: 321 to 321
 cd ~
Changed:
<
<
El alumno quedó muy triste, porque en 2 o 3 segundos le deshice la broma en la cual perdió horas.
>
>
El alumno se quedó muy triste, porque en 2 o 3 segundos le deshice la broma en la había perdido varias horas.
 
Changed:
<
<
Ahora vea bien! Si yo tuviera una máquina con Unix, habria hecho lo siguiente:
>
>
Ahora fíjate bien! Si yo tuviera una máquina con Unix, habria hecho lo siguiente:
 
$ tr ";" "\012" < confuso
Line: 331 to 331
 

X(com)primiendo con tr

Changed:
<
<
Ahora vea la diferencia entre los dos comandos date: el que hice hoy y el otro que fue ejecutado hace dos semanas:
>
>
Observa ahora la diferencia entre los dos comandos date: el que hice hoy y el otro que fue ejecutado hace dos semanas:
 
$ date # Hoy
Line: 354 to 354
 5
Changed:
<
<
Ahora observe porqué:
>
>
Ahora observa porqué:
 
$ date # Hace dos semanas Sun Sep 5 10:12:33 2004
Changed:
<
<
Como puedes notar, existen 2 caracteres en blanco antes del 5 (día), lo que embroma todo porque el tercer pedazo está vacio y el cuarto es el día (5). Entonces lo ideal sería comprimir los espacios en blanco sucesivos en solamente un espacio, para poder tratar las dos cadenas resultantes del comando date de la misma forma, y eso se hace así:
>
>
Como puedes notar, existen 2 caracteres en blanco antes del 5 (día), esto lo confunde todo porque el tercer pedazo está vacio y el cuarto es el día (5). Entonces lo ideal sería comprimir los espacios en blanco sucesivos en solamente un espacio, para poder tratar las dos cadenas resultantes del comando date de la misma forma, y eso se hace así:
 
$ date | tr -s " "a Sun Sep 5 10:12:33 2004
Changed:
<
<
Como puedes ver, no existen más los dos espacios, Entonces ahora podria cortar:
>
>
Como puedes ver, no existen los dos espacios, Entonces ahora podria cortar:
 
$ date | tr -s " " | cut -f 4 -d " " 10:12:33
Changed:
<
<
Viste como el Shell ya está solucionando problemas! Vea este archivo que fue bajado de una máquina con aquél sistema operacional que sufre de todos los vírus:
>
>
Viste como el Shell ya está solucionando problemas! Observa este archivo que fue bajado de una máquina con aquél sistema operativo que sufre de todos los vírus:
 
$ cat -ve ArqDoDOS.txt Este archivo^M$
Changed:
<
<
foi generado por^M$
>
>
fue generado por^M$
 DOS/Rwin y fue^M$ bajado por un^M$ ftp mal hecho.^M$
Line: 413 to 413
 
$ cat -ve ArchDeDOS?.txt Este archivo$
Changed:
<
<
foi generado por el$
>
>
fue generado por el$
 DOS/Rwin y fue$ bajado por un$ ftp mal hecho.$
Changed:
<
<
Bien, la opción -d del tr retira los caracteres especificados de todo el archivo. De esta forma retiré los caracteres no deseados, grabando en un archivo temporario de trabajo y posteriormente lo renombré con su nombre original.
>
>
Bien, la opción -d del tr retira los caracteres especificados de todo el archivo. De esta forma retiré los caracteres no deseados, grabandolo en un archivo de trabajo temporal y posteriormente lo renombré con su nombre original.
  Obs: En Unix debería hacer:
Line: 434 to 434
 Esto pasó porque el ftp fue hecho de modo binario (o image), o sea, sin la interpretación del texto. Si antes de la transmisión del archivo hubiera sido estipulada la opción ascii del ftp, esto no habría ocurrido.
Changed:
<
<
     - Mira, después de este consejo, estoy comenzando a gustar de ese tal de Shell, pero todavia hay mucha cosa que no consigo hacer.
>
>
     - Mira, después de este consejo, estoy comenzando a disfrutar de ese tal Shell, pero todavia hay muchas cosas que no consigo hacer.
 
Changed:
<
<
     - Claro!, si hasta aqui no te hablé casi nada sobre programación en Shell, tenemos mucha cosa por avanzar, sin embargo, con lo que aprendiste, ya dá para resolver muchos problemas, desde que tú adquieras el “modo Shell de pensar”. Serías capaz de hacer un script para decirme quienes son las personas que están “logadas” por más de un dia en tu servidor?
>
>
     - Claro!, si hasta aqui no te hablé casi nada sobre programación en Shell, tenemos muchas cosas aun por avanzar, sin embargo, con lo que aprendiste, ya te da para resolver muchos problemas, hasta que tú adquieras el “modo Shell de pensar”. Serías capaz de hacer un script para decirme quienes son las personas que están “logadas” desde hace más de un dia en tu servidor?
       - Claro que no! Para eso seria necesario que conociera los comandos condicionales que todavia no me explicaste como funcionan.
Changed:
<
<
    - Dejame intentar cambiar un pouco tu lógica y traerla para el “modo Shell de pensar”, pero antes es mejor tomar un chope... Chico!, traeme otros dos...
>
>
    - Dejame intentar cambiar un poco tu lógica y atraerla hacia el “modo Shell de pensar”, pero antes es mejor tomar un chope... Chico!, traeme otros dos...
 
Changed:
<
<
     - Ahora que ya mojé a palavra, vamos a resolver el problema que te propuse. Presta atención a como funciona el comando who:
>
>
     - Ahora que ya moje el gaznate, vamos a resolver el problema que te propuse. Presta atención a como funciona el comando who:
 
$ who
Line: 452 to 452
 lcarlos pts/3 Sep 20 10:01
Changed:
<
<
Y mira tambiém el date:
>
>
Y mira también el date:
 
$ date
Line: 469 to 469
 $ LANG=pt_BR date Seg Set 20 10:47:19 BRT 2004
Changed:
<
<
Y así pasas la salida del comando date para portugués, o para cualquier otro idioma que quieras.
>
>
Y así pasas la salida del comando date hacia portugués, o hacia cualquier otro idioma que quieras.
 
Changed:
<
<
Entonces, si en algún registro del who no encuentro la fecha de hoy, significa que el individuo está "logado" por más de un día, ya que él no puede haberse "logado" mañana... Vamos a guardar el pedazo que importa de la fecha de hoy para buscarla em la salida del who:
>
>
Entonces, si en algún registro del who no encuentro la fecha de hoy, significa que el individuo está "logado" hace más de un día, ya que él no puede haberse "logado" mañana... Vamos a guardar el pedazo que importa de la fecha de hoy para buscarla en la salida del who:
 
$ Fecha=$(date | cut -c 5-10)
Line: 485 to 485
 Sep 20
Changed:
<
<
Muy bien! Ahora, lo que tenemos que hacer es buscar en el comando who los registros que no poseen esta fecha.
>
>
Muy bien! Ahora, lo que tenemos que hacer es buscar con el comando who los registros que no poseen esta fecha.
 
Changed:
<
<
     - Ah! Me parece que estoy entendiendo! TAhora que mencionaste en buscar, se me ocurrió el comando grep, acerté?
>
>
     - Ah! Me parece que estoy entendiendo! Ahora que mencionaste lo de buscar, se me ocurrió el comando grep, acerté?
       - Correctísimo! Solo que tengo que usar el grep con aquella opción que solamente lista los registros en los quales no encontró la cadena. Te acuerdas que opción es esa?
Line: 507 to 507
 jneves
Changed:
<
<
     - Viste? No fue necesario usar ningún comando condicional, porque además nuestro comando condicional más usado, el famoso if, no verifica condición sino instrucciones, como veremos ahora.
>
>
     - Te diste cuenta? No fue necesario usar ningún comando condicional, porque además nuestro comando condicional más usado, el famoso if, no verifica condición sino instrucciones, como veremos ahora.
 

Comandos Condicionales

Changed:
<
<
Vea las líneas de comando que siguen:
>
>
Observa las líneas de comando que siguen:
 
Line: 537 to 537
       - y que hace ese $? por ahí? Comenzando por pesos ($) parece ser una variable, correcto?
Changed:
<
<
     - Si, es una variable que contiene el código de salida de la última instrucción ejecutada. Te puedo garantizar que si esta instrucción fué bien ejecutada, $? tendrá el valor cero, em caso contrario su valor será diferente de cero.
>
>
     - Si, es una variable que contiene el código de salida de la última instrucción ejecutada. Te puedo garantizar que si esta instrucción fué bien ejecutada, $? tendrá el valor cero, en caso contrario su valor será diferente de cero.
 

El Comando if

Changed:
<
<
Lo que nuestro comando condicional if hace es testar la variável $?. Entonces vamos a ver su sintáxis:
>
>
Lo que nuestro comando condicional if hace es testar la variable $?. Veamos entonces a ver su sintaxis:
 
    if cmd
    then
Line: 557 to 557
  fi
Changed:
<
<
o sea: en caso que el comando cmd halla sido ejecutado con éxito, los comandos del bloque del then (cmd1, cmd2 y cmdn) serán ejecutados, em el caso contrario, los comandos ejecutados serán los del bloque opcional del else (cmd3, cmd4 y cmdm), terminando con un fi.
>
>
o sea: en caso que el comando cmd haya sido ejecutado con éxito, los comandos del bloque del then (cmd1, cmd2 y cmdn) serán ejecutados, en caso contrario, los comandos ejecutados serán los del bloque opcional del else (cmd3, cmd4 y cmdm), terminando con un fi.
 
Changed:
<
<
Vamos a ver em la prática como eso funciona usando un scriptisiño que sirve para incluir usuários en el /etc/passwd:
>
>
Vamos a ver en la prática como funciona eso usando un scriptisiño que sirve para incluir usuários en el /etc/passwd:
 
$ cat incusu
Line: 578 to 578
 fi
Changed:
<
<
Nota que el if está verificando diretamente el comando grep y ésta es su finalidad. En caso de que el if sea exitoso, o sea, el usuário (cuyo nombre está en $1) fuera encontrado en /etc/passwd, los comandos del bloque del then serán ejecutados (en este ejemplo es solamente el echo) y en el caso contrario, las instrucciones del bloque del else son las que serán ejecutadas, cuando entonces un nuevo if verifica si el comando useradd fué bien ejecutado , creando el registro del usuario en /etc/passwd, o no cuando entonces dará el mensaje de error.
>
>
Nota que el if está verificando diretamente el comando grep y ésta es su finalidad. En caso de que el if sea exitoso, o sea, el usuário (cuyo nombre está en $1) fuera encontrado en /etc/passwd, los comandos del bloque del then serán ejecutados (en este ejemplo es solamente el echo) y en el caso contrario, las instrucciones del bloque del else son las que serán ejecutadas, entonces un nuevo if verifica si el comando useradd fué bien ejecutado , creando el registro del usuario en /etc/passwd, o no, y es entonces cuando dará el mensaje de error.
 Veamos su ejecución, primero pasando un usuario ya existente:

Line: 587 to 587
 Usuario 'jneves' ya existe
Changed:
<
<
Como ya vimos diversas veces, pero siempre es bueno insistir en el tema para que quedes alertado, en el ejemplo dado surgió una línea no deseada, ella es la salida del comando grep. Para evitar que eso pase, debemos desviar la salida de esta instrucción para /dev/null, quedando así:
>
>
Como ya vimos diversas veces, pero siempre es bueno insistir en el tema para que te quede claro, en el ejemplo anterior surgió una línea no deseada, esta es la salida del comando grep. Para evitar que eso pase, debemos desviar la salida de esta instrucción para /dev/null, quedando así:
 
$ cat incusu
Line: 616 to 616
 
Changed:
<
<
Epa!, aquél error no era para pasar! Para evitar que eso suceda debemos mandar também la salida de error (strerr, te acuerdas?) del useradd para /dev/null, quedando en la versión final así:
>
>
Epa!, aquél error no tenia que pasar! Para evitar que eso suceda debemos mandar también la salida de error (strerr, te acuerdas?) del useradd hacia /dev/null, quedando la versión final así:
 
$ cat incusu
Line: 649 to 649
 Usuario 'perez' ya existe
Changed:
<
<
Recuerdas que te dije que a lo largo de nuestras conversas y choppes nuestros programas irían a ir mejorando? Entonces veamos ahora como podríamos mejorar nuestro programa para incluir músicas:
>
>
Recuerdas que te dije que a lo largo de nuestras conversaciones y "choppes" nuestros programas irían mejorando? Entonces veamos ahora como podríamos mejorar nuestro programa para incluir músicas:
 
$ cat musinc
Line: 665 to 665
 fi
Changed:
<
<
Como viste, es una pequeña evolución de la versión anterior, de forma que, antes de incluir un registro (que por la versión anterior podría ser duplicado), verificamos si el registro comenzaba (^) y terminaba ($) igual al parámetro pasado ($1). El uso del circunflejo (^) en el inicio de la cadena y el pesos ($) en el fin, son para verificar si el parâmetro pasado (el álbum y sus datos) son exactamente iguales a algún registro anteriormente incluído y no unicamente igual a un pedazo de alguno de los registros.
>
>
Como viste, es una pequeña evolución de la versión anterior, de forma que, antes de incluir un registro (que con la versión anterior podría ser duplicado), verificamos si el registro comenzaba (^) y terminaba ($) igual al parámetro pasado ($1). El uso del circunflejo (^) en el inicio de la cadena y el pesos ($) en el fin, son para verificar si el parámetro pasado (el álbum y sus datos) son exactamente iguales a algún registro anteriormente incluído y no unicamente igual a un pedazo de alguno de los registros.
  Vamos a ejecutarlo pasando un álbum ya anteriormente incluído:
Line: 686 to 686
 album 5^Artista9~Musica9:Artista10~Musica10
Changed:
<
<
     - Como viste, el programa mejoró un poquito, pero todavia no está pronto. A medida que te vaya enseñando a programar en shell, nuestra CDteca va a ir quedando cada vez mejor.
>
>
     - Como viste, el programa mejoró un poquito, pero todavia no está listo. A medida que te vaya enseñando a programar en shell, nuestra CDteca va a ir quedando cada vez mejor.
       - Entendí todo lo que me explicaste, pero todavia no sé como hacer un if para verificar condiciones, o sea el uso normal del comando.
Changed:
<
<
     - Mira, para eso existe el comando test, él es el que verifica condiciones. El comando if verifica el comando test. Pero eso está medio confuso y como ya hablé mucho, esty precisando de unos choppes para mojar la palabra. Vamos a parar por aqui y en la próxima vez te explico claramente el uso del test y de diversas otras sintáxis del if.
>
>
     - Mira, para eso existe el comando test, él es quien verifica condiciones. El comando if verifica el comando test. Pero eso está medio confuso y como ya hablé mucho, estoy necesitando unos "choppes" para mojar las palabras. Vamos a parar por aqui y la próxima vez te explico claramente el uso del test y de diversas otras sintáxis del if.
       - Estamos de acuerdo entonces! Me parece bien porque yo tambiém estoy quedando tonto y así aprovecho para practicar esa cantidad de cosas de las cuales me hablaste hoy .
Changed:
<
<
     - Para fijar lo que aprendiste, trata de hacer un scriptiziño para informar si un determinado usuario, que será pasado como parámetro está logado (ajjjhh!) o no.
>
>
     - Para memorizar lo que aprendiste, trata de hacer un scriptiziño para informar si un determinado usuario, que será pasado como parámetro está logado (ajjjhh!) o no.
 
Changed:
<
<
     - Chico,dos choppes más por favor...
>
>
     - Chico,dos "choppes" más por favor...
 
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é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

Revision 513 Feb 2007 - JulioNeves

Line: 1 to 1
 

Conversa de Bar Parte III
<--pula duas linhas-->

Line: 700 to 700
  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
 
Deleted:
<
<
-- HumbertoPina - 03 Oct 2006
 -- HumbertoPina - 04 Oct 2006

Revision 409 Oct 2006 - Main.HumbertoPina

Line: 1 to 1
 

Conversa de Bar Parte III
<--pula duas linhas-->

Line: 329 to 329
 $ tr ";" "\012" < confuso
Changed:
<
<

Xprimiendo con tr

>
>

X(com)primiendo con tr

  Ahora vea la diferencia entre los dos comandos date: el que hice hoy y el otro que fue ejecutado hace dos semanas:

Revision 305 Oct 2006 - Main.HumbertoPina

Line: 1 to 1
 

Conversa de Bar Parte III
<--pula duas linhas-->

Line: 12 to 12
 

El Comando cut (que no es la central única de trabajadores)
<--pula duas linhas-->

Changed:
<
<
Primero te quiero mostrar, de forma eminentemente práctica una instrucción simple de usar y muy útil: el comando cut, Esta instrucción es usada para cortar un determinado pedazo de un archivo y tiene dos formas distintas de uso:
>
>
Primero te quiero mostrar, de forma eminentemente práctica, una instrucción simple de usar y muy útil: el comando cut, Esta instrucción es usada para cortar un determinado pedazo de un archivo y tiene dos formas distintas de uso:
 

El comando cut con la opción -c

Con esta opción, el comando tiene la siguiente sintáxis:

Changed:
<
<
     cut -c PosIni?-PosFim [archivo]
>
>
     cut -c PosIni?-PosFin [archivo]
 

Donde:

     PosIni = Posición inicial

Changed:
<
<
     PosFim = Posición  final
>
>
     PosFin = Posición  final
 

Line: 62 to 62
 9875789
Changed:
<
<
Como dá para ver, en realidad existen cuatro sintáxis distintas: en la primera (-c 1-5), especifiqué una faja de posiciones, en la segunda (-c -6), especifiqué todo hasta una determinada posición, en la tercera (-c 4-) de una determinada posición en adelante y en la cuarta (-c 1,3,5,7,9), determinadas posiciones. La última (-c -3,5,8-) fue solamente para mostrar que podemos mesclar todo.
>
>
Como dá para ver, en realidad existen cuatro sintáxis distintas: en la primera (-c1-5), especifiqué una faja de posiciones, en la segunda (-c-6), especifiqué todas las posiciones hasta una determinada columna, en la tercera (-c4-) de una determinada posición en adelante y en la cuarta (-c1,3,5,7,9), determinadas posiciones. La última (-c-3,5,8-) fue solamente para mostrar que podemos mesclar todo.
 

El comando cut con la opción -f

Changed:
<
<
Pero no pienses que acabó por ahí! Como debes haber notado, esta forma de cut es útil para archivos con campos de tamaño fijo, sin embargo, actualmente lo que más existe son archivos con campos de tamaño variables, donde cada campo termina con un delimitador. Vamos a dar una ojeada en el archivo musicas que comenzamos a preparar en nuestra conversa de la última vez que estuvimos aqui en el bar.
>
>
Pero no pienses que acabó por ahí! Como debes haber notado, esta forma de cut es útil para archivos con campos de tamaño fijo, sin embargo, actualmente lo que más existe son archivos con campos de tamaño variables, donde cada campo termina con un delimitador. Vamos a dar una ojeada en el archivo musicas que comenzamos a preparar en nuestra conversa de la última vez que estuvimos aqui, en el bar.
 
$ cat musicas
Line: 80 to 80
       nombre del album^intérprete1~nombre de la música1:...:intérpreten~nombre de la músican
Changed:
<
<
O sea, el nombre del álbum será separado por un circunflejo (^) del resto del registro, que está formado por diversos grupos compuestos por el intérprete de cada música del CD y la respectiva música interpretada. Estos grupos son separados entre sí por dos puntos (:) e internamente, el nombre del intérprete será separado por un til (~) del nombre de la música.
>
>
O sea, el nombre del álbum será separado por un circunflejo (^) del resto del registro, que está formado por diversos grupos, compuestos por el intérprete de cada música del CD y la respectiva música interpretada. Estos grupos son separados entre sí por dos puntos (:) e internamente, el nombre del intérprete será separado por un til (~), del nombre de la música.
  Entonces para sacar los datos referentes a todas las segundas músicas del archivo musicas, debemos hacer:
Line: 92 to 92
 Artista8~Musica8
Changed:
<
<
O sea, cortamos el segundo campo (-f de field en inglés) delimitado (-d) por dos puntos (:). Pero en cambio, se quisieramos solamente los intérpretes, debemos hacer:
>
>
O sea, cortamos el segundo campo (-f de field en inglés), delimitado (-d) por dos puntos (:). En cambio, se quisieramos solamente los intérpretes, podemos hacer:
 
$ cut -f2 -d: musicas | cut -f1 -d~
Line: 102 to 102
 Artista8
Changed:
<
<
Para entender eso, vamos a sacar la primera línea de musicas:
>
>
Para entender esto, vamos a sacar la primera línea de musicas:
 
$ head -1 musicas album 1^Artista1~Musica1:Artista2~Musica2
Changed:
<
<
Entonces, observe lo que fue hecho:
>
>
Ahora observe lo que fue hecho:
  Delimitador del primero cut (:)

     album 1^Artista1~Musica1:Artista2~Musica2

Changed:
<
<
De esta forma, en el primero cut, el primer campo del delimitador (-d) dos puntos (:) es album 1^Artista1~Musica1 y el segundo, que es lo que nos interesa, es Artista2~Musica2.
>
>
De esta forma, en el primero cut, el primer campo del delimitador (-d) dos puntos (:), es album 1^Artista1~Musica1 y el segundo, que es lo que nos interesa, es Artista2~Musica2.
  Vamos ahora a ver lo que pasó con el segundo cut:
Line: 123 to 123
       Artista2~Musica2
Changed:
<
<
Ahora, primer campo del delimitador (-d) til (~), que es el que nos interesa, é Artista2 y el segundo es Musica2.
>
>
Ahora, el primer campo del delimitador (-d) til (~), que es el que nos interesa, é Artista2 y el segundo es Musica2.
 
Changed:
<
<
Si el racionamiento que hicimos para la primera línea fuera aplicado en el resto del archivo, llegaremos a la respuesta anteriormente dada.
>
>
Si el razonamiento que hicimos para la primera línea fuera aplicado en el resto del archivo, llegariamos a la respuesta anteriormente dada.
 

Si hay cut hay paste

Changed:
<
<
Como ya era de esperar, el comando paste sirve para pegar, solo que aqui en Shell lo que pega son archivos. Solo para comenzar a entenderlo, vamos a hacer así::
>
>
Como ya era de esperar, el comando paste sirve para pegar, sólo que aqui en Shell lo que pega son archivos. Para comenzar a entenderlo, vamos a hacer así::
 
    paste arch1 arch2
Changed:
<
<
De esta forma él mandará para la salida padrón (stdout) cada uno de los registros de arch1 al lado de los registros de arch2 correspondientes y en caso de que ningún delimitador sea especificado, usará por default el <TAB>.
>
>
De esta forma el comando mandará para la salida padrón (stdout) cada uno de los registros de arch1, al lado de los registros de arch2 correspondientes y en caso de que ningún delimitador sea especificado, usará por default el <TAB>.
  El paste es un comando poco usado por su sintáxis ser poco conocida. Vamos a jugar con 2 archivos creados de la siguiente forma:
Line: 160 to 160
 10
Changed:
<
<

Quién está en pié, se acuesta

>
>

Quién está de pié, se acuesta.

  Ahora vamos a transformar la columna del pares en línea:
Line: 178 to 178
 2+4+6+8+10
Changed:
<
<
e después pasaríamos esta línea para la calculadora (bc) y entonces quedaria:
>
>
y después pasaríamos esta línea con pipe (|) para la calculadora (bc), que entonces quedaria:
 
$ paste -sd'+' pares | bc
Line: 230 to 230
 

El Comando tr

Changed:
<
<
Otro comando muy interesante es el tr que sirve para substituir, comprimir o retirar caracteres. Su sintáxis sigue el siguiente padrón:
>
>
Otro comando muy interesante es el tr que sirve para substituir, comprimir o retirar caracteres. Su sintáxis sigue el siguiente padrón:
 
    tr [opciones] cadena1 [cadena2]
Changed:
<
<
El comando tr copia el texto de la entrada padrón (stdin) y cambia las veces que halle los caracteres de cadena1 por el correspondiente contenido de la cadena2 o cambia las múltiples ocurrencias de los caracteres de cadena1 por solamente un caracter, o todavia puede retirar los caracteres de la cadena1.
>
>
El comando tr copia el texto de la entrada padrón (stdin) y cambia, las veces que halle los caracteres de cadena1 por el correspondiente contenido de la cadena2, o cambia las múltiples ocurrencias de los caracteres de cadena1 por solamente un caracter, o todavia puede retirar los caracteres de la cadena1.
  Las principales opciones del comando son:
Line: 244 to 244
 
Principales Opciones del comando tr
  Opción     Significado  
Changed:
<
<
-s   Comprime n ocurrencias de la cadena1 en solo una  
>
>
-s   Comprime n ocurrencias de la cadena1 en sólo una  
 
-d   Retira del archivo los caracteres de la cadena1  
Line: 257 to 257
 baba
Changed:
<
<
O sea, cambié todas sas ocurrencias de la letra o por la letra a.
>
>
O sea, cambié todas esas ocurrencias de la letra o por la letra a.
 
Changed:
<
<
Suponga que en un determinado punto de mi script pido al operador para teclear s o n (si o no), y guardo su respuesta em la variable $Resp. El contenido de $Resp puede estar con letra mayúscula o minúscula, y de esta forma tendria que hacer diversos tests para saber si la respuesta dada fue S, s, N o n. Entonces lo mejor es hacer:
>
>
Suponga que en un determinado punto de mi script, pido al operador para teclear s o n (si o no), y guardo su respuesta en la variable $Resp. El contenido de $Resp puede estar con letra mayúscula o minúscula, y de esta forma tendria que hacer diversos tests para saber si la respuesta dada fue S, s, N o n. Entonces lo mejor es hacer:
 
$ Resp=$(echo $Resp | tr SN sn)
Line: 292 to 292
 

Sacando caracteres con tr

Changed:
<
<
Entonces dejame contarte un "causo": un alumno que estaba enojado conmigo, resolvió complicar mi vida y en un ejercicio práctico valiendo nota, que pasé para ser hecho en el computador, me entregó el script con todos los comandos separados por punto y coma (recuerdas que te dije que el punto y coma servía para separar diversos comandos en una misma línea?).
>
>
Entonces dejame contarte un "causo": un alumno que estaba enojado conmigo, resolvió complicar mi vida y en un ejercicio práctico, valiendo nota, que pasé para ser hecho en el computador, me entregó el script con todos los comandos separados por punto y coma (recuerdas que te dije que el punto y coma servía para separar diversos comandos en una misma línea?).
  Voy a dar un ejemplo simplificado e idiota de un "chorizo" así:
Line: 310 to 310
 confuso livro musexc musicas musinc muslist numeros
Changed:
<
<
Pero prueba es cosa seria (y billete de dólar es todavia más :)) entonces, para entender lo que el aluno habia hecho, lo llamé y en su frente ejecuté el siguiente comando:
>
>
Pero nota de prueba es cosa seria (y billete de dólar es todavia más smile ) entonces, para entender lo que el aluno habia hecho, lo llamé y en su frente ejecuté el siguiente comando:
 
$ tr ";" "\n" < confuso
Line: 323 to 323
  El alumno quedó muy triste, porque en 2 o 3 segundos le deshice la broma en la cual perdió horas.
Changed:
<
<
Ahora vea bien! Si yo tuviera una máquina con Unix, habria hecho en cambio:
>
>
Ahora vea bien! Si yo tuviera una máquina con Unix, habria hecho lo siguiente:
 
$ tr ";" "\012" < confuso
Line: 331 to 331
 

Xprimiendo con tr

Changed:
<
<
Ahora vea la diferencia entre los dos comandos date: el que hice hoy y otro que fue ejecutado hace dos semanas:
>
>
Ahora vea la diferencia entre los dos comandos date: el que hice hoy y el otro que fue ejecutado hace dos semanas:
 
$ date # Hoy
Line: 347 to 347
 14:59:54
Changed:
<
<
Sin embargo, dos semanas antes ocurriria lo siguiente:
>
>
Sin embargo, dos semanas antes ocurriría lo siguiente:
 
$ date | cut -f 4 -d ' '
Line: 361 to 361
 Sun Sep 5 10:12:33 2004
Changed:
<
<
Como puedes notar, existen 2 caracteres en blanco antes del 5 (día), lo que embroma todo porque el tercer pedazo está vacio y el cuarto es el día (5). Entonces lo ideal sería comprimir los espacios en blanco sucesivos en solamente un espacio para poder tratar las dos cadenas resultantes del comando date de la misma forma, y eso se hace así:
>
>
Como puedes notar, existen 2 caracteres en blanco antes del 5 (día), lo que embroma todo porque el tercer pedazo está vacio y el cuarto es el día (5). Entonces lo ideal sería comprimir los espacios en blanco sucesivos en solamente un espacio, para poder tratar las dos cadenas resultantes del comando date de la misma forma, y eso se hace así:
 
$ date | tr -s " "a
Line: 375 to 375
 10:12:33
Changed:
<
<
Mira ahí, vé como el Shell ya está solucionando problemas!. Vea este archivo que fue bajado de una máquina con aquél sistema operacional que sufre de todos los vírus:
>
>
Viste como el Shell ya está solucionando problemas! Vea este archivo que fue bajado de una máquina con aquél sistema operacional que sufre de todos los vírus:
 
Line: 434 to 434
 Esto pasó porque el ftp fue hecho de modo binario (o image), o sea, sin la interpretación del texto. Si antes de la transmisión del archivo hubiera sido estipulada la opción ascii del ftp, esto no habría ocurrido.
Changed:
<
<
     - Mira, después de este consejo, estoy comenzando a gustar de este tal de Shell, pero todavia hay mucha cosa que no consigo hacer.
>
>
     - Mira, después de este consejo, estoy comenzando a gustar de ese tal de Shell, pero todavia hay mucha cosa que no consigo hacer.
 
Changed:
<
<
     - Claro!, hasta aqui no te hablé casi nada sobre programación en Shell, tenemos mucha cosa para aprender, sin embargo, con lo que aprendiste, ya dá para resolver muchos problemas, desde que tú adquieras el “modo Shell de pensar”. Serías capaz de hacer un script para decirme quienes son las personas que están “logadas” por más de un dia en tu servidor?
>
>
     - Claro!, si hasta aqui no te hablé casi nada sobre programación en Shell, tenemos mucha cosa por avanzar, sin embargo, con lo que aprendiste, ya dá para resolver muchos problemas, desde que tú adquieras el “modo Shell de pensar”. Serías capaz de hacer un script para decirme quienes son las personas que están “logadas” por más de un dia en tu servidor?
       - Claro que no! Para eso seria necesario que conociera los comandos condicionales que todavia no me explicaste como funcionan.

    - Dejame intentar cambiar un pouco tu lógica y traerla para el “modo Shell de pensar”, pero antes es mejor tomar un chope... Chico!, traeme otros dos...

Changed:
<
<
     - Ahora que ya mojéi a palavra, vamos a resolver el problema que te propuse. Nota como funciona el comando who:
>
>
     - Ahora que ya mojé a palavra, vamos a resolver el problema que te propuse. Presta atención a como funciona el comando who:
 
$ who
Line: 459 to 459
 Mon Sep 20 10:47:19 BRT 2004
Changed:
<
<
Ves que el mes y el dia están em el mismo formato en ambos comandos?
>
>
Ves que el mes y el dia están en el mismo formato en ambos comandos?
 
Pinguim com placa de dica Algunas vezes un comando tiene la salida en portugués y el otro en inglés. Cuando eso pase, puedes usar el siguiente artificio:
Line: 469 to 469
 $ LANG=pt_BR date Seg Set 20 10:47:19 BRT 2004
Changed:
<
<
Y así pasas la salida del comando date para portugués, o para otro idioma que quieras.
>
>
Y así pasas la salida del comando date para portugués, o para cualquier otro idioma que quieras.
 

Entonces, si en algún registro del who no encuentro la fecha de hoy, significa que el individuo está "logado" por más de un día, ya que él no puede haberse "logado" mañana... Vamos a guardar el pedazo que importa de la fecha de hoy para buscarla em la salida del who:

Line: 487 to 487
  Muy bien! Ahora, lo que tenemos que hacer es buscar en el comando who los registros que no poseen esta fecha.
Changed:
<
<
     - Ah! Me parece que estoy entendiendo! Tu mencionaste en buscar y se me ocurrió el comando grep, acerté?
>
>
     - Ah! Me parece que estoy entendiendo! TAhora que mencionaste en buscar, se me ocurrió el comando grep, acerté?
 
Changed:
<
<
     - Correctísimo! Solo que tengo que usar el grep con aquella opción que solamente lista sos registros em los quales él no encontró la cadena. Te acuerdas que opción es esa?
>
>
     - Correctísimo! Solo que tengo que usar el grep con aquella opción que solamente lista los registros en los quales no encontró la cadena. Te acuerdas que opción es esa?
       - Claro, es la opción -v...
Line: 573 to 573
  then echo Usuario \'$1\' incluído en /etc/passwd else
Changed:
<
<
echo "Problemas em el catastro. Usted es root?"
>
>
echo "Problemas en el catastro. Usted es root?"
  fi fi
Line: 593 to 593
 $ cat incusu #!/bin/bash # Versión 2
Changed:
<
<
if grep ^$1 /etc/passwd > /dev/null # ou: if grep -q ^$1 /etc/passwd
>
>
if grep ^$1 /etc/passwd > /dev/null # o: if grep -q ^$1 /etc/passwd
 then echo Usuario \'$1\' ya existe else

Revision 205 Oct 2006 - JulioNeves

Line: 1 to 1
 

Conversa de Bar Parte III
<--pula duas linhas-->

Line: 430 to 430
 
Changed:
<
<
%ATENCIÓN_INI%
>
>
Pinguim com placa de atenção (em espanhol)
 Esto pasó porque el ftp fue hecho de modo binario (o image), o sea, sin la interpretación del texto. Si antes de la transmisión del archivo hubiera sido estipulada la opción ascii del ftp, esto no habría ocurrido.
Changed:
<
<
%ATENCIÓN_FIM%
>
>
       - Mira, después de este consejo, estoy comenzando a gustar de este tal de Shell, pero todavia hay mucha cosa que no consigo hacer.

Revision 104 Oct 2006 - Main.HumbertoPina

Line: 1 to 1
Added:
>
>

Conversa de Bar Parte III
<--pula duas linhas-->

    - Mozo, traiga dos choppes por favor, que hoy voy a tener que hablar mucho.

Trabajando con cadenas

Por el título encima no pienses que te voy a enseñar a ser carcelero! Me estoy referiendo a cadena de caracteres!

El Comando cut (que no es la central única de trabajadores)
<--pula duas linhas-->

Primero te quiero mostrar, de forma eminentemente práctica una instrucción simple de usar y muy útil: el comando cut, Esta instrucción es usada para cortar un determinado pedazo de un archivo y tiene dos formas distintas de uso:

El comando cut con la opción -c

Con esta opción, el comando tiene la siguiente sintáxis:

     cut -c PosIni-PosFim [archivo]

Donde:

     PosIni = Posición inicial
     PosFim = Posición  final

$ cat números 1234567890 0987654321 1234554321 9876556789 $ cut -c1-5 números 12345 09876 12345 98765 $ cut -c-6 números 123456 098765 123455 987655 $ cut -c4- números 4567890 7654321 4554321 6556789 $ cut -c1,3,5,7,9 números 13579 08642 13542 97568 $ cut -c -3,5,8- números 1235890 0986321 1235321 9875789

Como dá para ver, en realidad existen cuatro sintáxis distintas: en la primera (-c 1-5), especifiqué una faja de posiciones, en la segunda (-c -6), especifiqué todo hasta una determinada posición, en la tercera (-c 4-) de una determinada posición en adelante y en la cuarta (-c 1,3,5,7,9), determinadas posiciones. La última (-c -3,5,8-) fue solamente para mostrar que podemos mesclar todo.

El comando cut con la opción -f

Pero no pienses que acabó por ahí! Como debes haber notado, esta forma de cut es útil para archivos con campos de tamaño fijo, sin embargo, actualmente lo que más existe son archivos con campos de tamaño variables, donde cada campo termina con un delimitador. Vamos a dar una ojeada en el archivo musicas que comenzamos a preparar en nuestra conversa de la última vez que estuvimos aqui en el bar.

$ cat musicas album 1^Artista1~Musica1:Artista2~Musica2 album 2^Artista3~Musica3:Artista4~Musica4 album 3^Artista5~Musica5:Artista6~Musica5 album 4^Artista7~Musica7:Artista8~Musica8

Entonces, recapitulando, su "layout" es el siguiente:

     nombre del album^intérprete1~nombre de la música1:...:intérpreten~nombre de la músican

O sea, el nombre del álbum será separado por un circunflejo (^) del resto del registro, que está formado por diversos grupos compuestos por el intérprete de cada música del CD y la respectiva música interpretada. Estos grupos son separados entre sí por dos puntos (:) e internamente, el nombre del intérprete será separado por un til (~) del nombre de la música.

Entonces para sacar los datos referentes a todas las segundas músicas del archivo musicas, debemos hacer:

$ cut -f2 -d: musicas Artista2~Musica2 Artista4~Musica4 Artista6~Musica5 Artista8~Musica8

O sea, cortamos el segundo campo (-f de field en inglés) delimitado (-d) por dos puntos (:). Pero en cambio, se quisieramos solamente los intérpretes, debemos hacer:

$ cut -f2 -d: musicas | cut -f1 -d~ Artista2 Artista4 Artista6 Artista8

Para entender eso, vamos a sacar la primera línea de musicas:

$ head -1 musicas album 1^Artista1~Musica1:Artista2~Musica2

Entonces, observe lo que fue hecho:

Delimitador del primero cut (:)

     album 1^Artista1~Musica1:Artista2~Musica2

De esta forma, en el primero cut, el primer campo del delimitador (-d) dos puntos (:) es album 1^Artista1~Musica1 y el segundo, que es lo que nos interesa, es Artista2~Musica2.

Vamos ahora a ver lo que pasó con el segundo cut:

Nuevo delimitador (~)

     Artista2~Musica2

Ahora, primer campo del delimitador (-d) til (~), que es el que nos interesa, é Artista2 y el segundo es Musica2.

Si el racionamiento que hicimos para la primera línea fuera aplicado en el resto del archivo, llegaremos a la respuesta anteriormente dada.

Si hay cut hay paste

Como ya era de esperar, el comando paste sirve para pegar, solo que aqui en Shell lo que pega son archivos. Solo para comenzar a entenderlo, vamos a hacer así::

    paste arch1 arch2

De esta forma él mandará para la salida padrón (stdout) cada uno de los registros de arch1 al lado de los registros de arch2 correspondientes y en caso de que ningún delimitador sea especificado, usará por default el <TAB>.

El paste es un comando poco usado por su sintáxis ser poco conocida. Vamos a jugar con 2 archivos creados de la siguiente forma:

$ seq 10 > enteros $ seq 2 2 10 > pares

Para ver el contenido de los archivos creados, vamos a usar el paste en su forma simple que mostramos arriba:

$ paste enteros pares 1 2 2 4 3 6 4 8 5 10 6 7 8 9 10

Quién está en pié, se acuesta

Ahora vamos a transformar la columna del pares en línea:

$ paste -s pares 2 4 6 8 10

Usando separadores

Como ya fue dicho, el separador default del paste es el <TAB>, pero eso puede ser alterado con la opción -d. Entonces para calcular la suma del contenido de pares primeramente hariamos:

$ paste -s -d'+' pares # tambiém podria ser -sd'+' 2+4+6+8+10

e después pasaríamos esta línea para la calculadora (bc) y entonces quedaria:

$ paste -sd'+' pares | bc 30

De esta forma, para calcular el factorial del número contenido en $Num, basta hacer:

$ seq $Num | paste -sd'*' | bc

Con el comando paste tu tambiém puedes montar formatos exóticos como este a seguir:

$ ls | paste -s -d'\t\t\n' arch1 arch2 arch3 arch4 arch5 arch6

Lo que pasó fue lo siguiente: fue especificado para el comando paste que tendria que transformar líneas en columnas (por la opción -s) y que sus separadores (si...! El acepta más de uno, pero solamente uno después de cada columna creada por el comando) serían un <TAB>, otra <TAB> y un <ENTER>, generando de esta forma su salida tabulada en 3 columnas.

Ahora que ya entendiste esto, ve como hacer la misma cosa, pero de forma más fácil, menos extraña y primitiva, usando el mismo comando pero con la siguiente sintáxis:

$ ls | paste - - - arch1 arch2 arch3 arch4 arch5 arch6

Y esto sucede porque si em vez de especificar los archivos colocamos el signo de menos (-), el comando paste los substituye por la salida o entrada padrón conforme el caso. En el ejemplo anterior los datos fueran mandados para la salida padrón (stdout), porque el pipe (|) estaba desviando la salida del ls para la entrada padrón (stdin) del paste, pero vea el ejemplo a seguir:

$ cat arch1 predisposición privilegiado profesional $ cat arch2 ver mario motor $ cut -c-3 arq1 | paste -d "" - arq2 prever primario promotor

En este caso, el cut devolvió las tres primeras letras de cada registro de arch1, el paste fue montado para no tener separador (-d"") y recibir la entrada padrón (desviada por el pipe) en el trazo (-), generando la salida junto con arch2.

El Comando tr

Otro comando muy interesante es el tr que sirve para substituir, comprimir o retirar caracteres. Su sintáxis sigue el siguiente padrón:

    tr [opciones] cadena1 [cadena2]

El comando tr copia el texto de la entrada padrón (stdin) y cambia las veces que halle los caracteres de cadena1 por el correspondiente contenido de la cadena2 o cambia las múltiples ocurrencias de los caracteres de cadena1 por solamente un caracter, o todavia puede retirar los caracteres de la cadena1.

Las principales opciones del comando son:

Principales Opciones del comando tr
-d   Retira del archivo los caracteres de la cadena1  
  Opción     Significado  
-s   Comprime n ocurrencias de la cadena1 en solo una  

Cambiando caracteres con tr

Primero te voy a dar un ejemplo bien bobo:

$ echo bobo | tr o a baba

O sea, cambié todas sas ocurrencias de la letra o por la letra a.

Suponga que en un determinado punto de mi script pido al operador para teclear s o n (si o no), y guardo su respuesta em la variable $Resp. El contenido de $Resp puede estar con letra mayúscula o minúscula, y de esta forma tendria que hacer diversos tests para saber si la respuesta dada fue S, s, N o n. Entonces lo mejor es hacer:

$ Resp=$(echo $Resp | tr SN sn)

y luego de este comando tendria seguridade de que el contenido de $Resp seria un s o un n.

Si mi archivo ArchEnt está todo escrito con letras mayúsculas y deseo pasarlas para minúsculas hago:

$ tr A-Z a-z < ArchEnt > /tmp/$$ $ mv -f /tmp/$$ ArchEnt

Note que em este caso usé la notacióno A-Z para no tener que escribir ABCD...YZ. Otro tipo de notación que puede ser usada son las escape sequences (preferiria escribir en español, pero en este caso como lo traduciría? Secuencias de escape? Medio sin sentido, no te parece? Pero continuemos...) que tambiém son reconocidas por otros comandos y también en lenguaje C, y cuyo significado verás a seguir:

Escape Sequences
\\   Una barra invertida   \0134
  Secuencia     Significado     Octal  
\t   Tabulación   \011
\n   Nueva línea   \012
\v   Tabulación Vertical   \013
\f   Nueva Página   \014
\r   Início de línea <^M>   \015

Sacando caracteres con tr

Entonces dejame contarte un "causo": un alumno que estaba enojado conmigo, resolvió complicar mi vida y en un ejercicio práctico valiendo nota, que pasé para ser hecho en el computador, me entregó el script con todos los comandos separados por punto y coma (recuerdas que te dije que el punto y coma servía para separar diversos comandos en una misma línea?).

Voy a dar un ejemplo simplificado e idiota de un "chorizo" así:

$ cat confuso echo lea Programación Shell Linux de Julio Cezar Neves > libro;cat libro;pwd;ls;rm -f lixo 2>/dev/null;cd ~

Yo ejecutaba el programa y él funcionaba:

$ confuso lea Programación Shell Linux de Julio Cezar Neves /home/jneves/LM confuso livro musexc musicas musinc muslist numeros

Pero prueba es cosa seria (y billete de dólar es todavia más :)) entonces, para entender lo que el aluno habia hecho, lo llamé y en su frente ejecuté el siguiente comando:

$ tr ";" "\n" < confuso echo lea Programación Shell Linux de Julio Cezar Neves pwd ls rm -f lixo 2>/dev/null cd ~

El alumno quedó muy triste, porque en 2 o 3 segundos le deshice la broma en la cual perdió horas.

Ahora vea bien! Si yo tuviera una máquina con Unix, habria hecho en cambio:

$ tr ";" "\012" < confuso

Xprimiendo con tr

Ahora vea la diferencia entre los dos comandos date: el que hice hoy y otro que fue ejecutado hace dos semanas:

$ date # Hoy Sun Sep 19 14:59:54 2006 $ date # Hace dos semanas Sun Sep 5 10:12:33 2006

Para ver la hora debería hacer:

$ date | cut -f 4 -d ' ' 14:59:54

Sin embargo, dos semanas antes ocurriria lo siguiente:

$ date | cut -f 4 -d ' ' 5

Ahora observe porqué:

$ date # Hace dos semanas Sun Sep 5 10:12:33 2004

Como puedes notar, existen 2 caracteres en blanco antes del 5 (día), lo que embroma todo porque el tercer pedazo está vacio y el cuarto es el día (5). Entonces lo ideal sería comprimir los espacios en blanco sucesivos en solamente un espacio para poder tratar las dos cadenas resultantes del comando date de la misma forma, y eso se hace así:

$ date | tr -s " "a Sun Sep 5 10:12:33 2004

Como puedes ver, no existen más los dos espacios, Entonces ahora podria cortar:

$ date | tr -s " " | cut -f 4 -d " " 10:12:33

Mira ahí, vé como el Shell ya está solucionando problemas!. Vea este archivo que fue bajado de una máquina con aquél sistema operacional que sufre de todos los vírus:

$ cat -ve ArqDoDOS.txt Este archivo^M$ foi generado por^M$ DOS/Rwin y fue^M$ bajado por un^M$ ftp mal hecho.^M$

y ahora te quiero dar dos consejos:

Pinguim com placa de dica Consejo #1 - La opción -v del cat muestra los caracteres de control invisibles, con la notación ^L, donde ^ es la tecla control y L es la respectiva letra. La opción -e muestra el final de la línea como un signo de pesos ($).

Pinguim com placa de dica Consejo #2 - Esto ocurre porque en formato DOS (o rwin), el fin de los registros está formado por un carriage-return (\r) y un line-feed (\n). En Linux sin embargo, el final del registro tiene solamente el line-feed.

Vamos entonces a limpiar este archivo.

$ tr -d '\r' < ArchDeDOS.txt > /tmp/$$ $ mv -f /tmp/$$ ArchDeDOS.txt

Ahora vamos a ver lo que pasó:

$ cat -ve ArchDeDOS.txt Este archivo$ foi generado por el$ DOS/Rwin y fue$ bajado por un$ ftp mal hecho.$

Bien, la opción -d del tr retira los caracteres especificados de todo el archivo. De esta forma retiré los caracteres no deseados, grabando en un archivo temporario de trabajo y posteriormente lo renombré con su nombre original.

Obs: En Unix debería hacer:

$ tr -d '\015' < ArchDeDOS.txt > /tmp/$$

%ATENCIÓN_INI% Esto pasó porque el ftp fue hecho de modo binario (o image), o sea, sin la interpretación del texto. Si antes de la transmisión del archivo hubiera sido estipulada la opción ascii del ftp, esto no habría ocurrido. %ATENCIÓN_FIM%

     - Mira, después de este consejo, estoy comenzando a gustar de este tal de Shell, pero todavia hay mucha cosa que no consigo hacer.

     - Claro!, hasta aqui no te hablé casi nada sobre programación en Shell, tenemos mucha cosa para aprender, sin embargo, con lo que aprendiste, ya dá para resolver muchos problemas, desde que tú adquieras el “modo Shell de pensar”. Serías capaz de hacer un script para decirme quienes son las personas que están “logadas” por más de un dia en tu servidor?

     - Claro que no! Para eso seria necesario que conociera los comandos condicionales que todavia no me explicaste como funcionan.

    - Dejame intentar cambiar un pouco tu lógica y traerla para el “modo Shell de pensar”, pero antes es mejor tomar un chope... Chico!, traeme otros dos...

     - Ahora que ya mojéi a palavra, vamos a resolver el problema que te propuse. Nota como funciona el comando who:

$ who jneves pts/1 Sep 18 13:40 rtorres pts/0 Sep 20 07:01 rlegaria pts/1 Sep 20 08:19 lcarlos pts/3 Sep 20 10:01

Y mira tambiém el date:

$ date Mon Sep 20 10:47:19 BRT 2004

Ves que el mes y el dia están em el mismo formato en ambos comandos?

Pinguim com placa de dica Algunas vezes un comando tiene la salida en portugués y el otro en inglés. Cuando eso pase, puedes usar el siguiente artificio:
$ date Mon Sep 20 10:47:19 BRT 2004 $ LANG=pt_BR date Seg Set 20 10:47:19 BRT 2004
Y así pasas la salida del comando date para portugués, o para otro idioma que quieras.

Entonces, si en algún registro del who no encuentro la fecha de hoy, significa que el individuo está "logado" por más de un día, ya que él no puede haberse "logado" mañana... Vamos a guardar el pedazo que importa de la fecha de hoy para buscarla em la salida del who:

$ Fecha=$(date | cut -c 5-10)

Aquí usé la construcción $(...), para dar prioridad a la ejecución de los comandos antes de atribuir a su salida a la variable $Fecha. Vamos a ver si funcionó:

$ echo $Fecha Sep 20

Muy bien! Ahora, lo que tenemos que hacer es buscar en el comando who los registros que no poseen esta fecha.

     - Ah! Me parece que estoy entendiendo! Tu mencionaste en buscar y se me ocurrió el comando grep, acerté?

     - Correctísimo! Solo que tengo que usar el grep con aquella opción que solamente lista sos registros em los quales él no encontró la cadena. Te acuerdas que opción es esa?

     - Claro, es la opción -v...

     - Eso mismo! Estás quedando un lujo! Entonces vamos a ver:

$ who | grep -v "$Fecha" jneves pts/1 Sep 18 13:40

     - Y si quisiera un poco mas de adornos,haría así:

$ who | grep -v "$Fecha" | cut -f1 -d ' ' jneves

     - Viste? No fue necesario usar ningún comando condicional, porque además nuestro comando condicional más usado, el famoso if, no verifica condición sino instrucciones, como veremos ahora.

Comandos Condicionales

Vea las líneas de comando que siguen:

$ ls musicas musicas $ echo $? 0 $ ls ArchInexistente ls: ArchInexistente: No such file or directory $ echo $? 1 $ who | grep jneves jneves pts/1 Sep 18 13:40 (10.2.4.144) $ echo $? 0 $ who | grep juliana $ echo $? 1

     - y que hace ese $? por ahí? Comenzando por pesos ($) parece ser una variable, correcto?

     - Si, es una variable que contiene el código de salida de la última instrucción ejecutada. Te puedo garantizar que si esta instrucción fué bien ejecutada, $? tendrá el valor cero, em caso contrario su valor será diferente de cero.

El Comando if

Lo que nuestro comando condicional if hace es testar la variável $?. Entonces vamos a ver su sintáxis:

    if cmd
    then
        cmd1
        cmd2
        cmdn
    else
        cmd3
        cmd4
        cmdm
    fi

o sea: en caso que el comando cmd halla sido ejecutado con éxito, los comandos del bloque del then (cmd1, cmd2 y cmdn) serán ejecutados, em el caso contrario, los comandos ejecutados serán los del bloque opcional del else (cmd3, cmd4 y cmdm), terminando con un fi.

Vamos a ver em la prática como eso funciona usando un scriptisiño que sirve para incluir usuários en el /etc/passwd:

$ cat incusu #!/bin/bash # Versión 1 if grep ^$1 /etc/passwd then echo Usuario \'$1\' ya existe else if useradd $1 then echo Usuario \'$1\' incluído en /etc/passwd else echo "Problemas em el catastro. Usted es root?" fi fi

Nota que el if está verificando diretamente el comando grep y ésta es su finalidad. En caso de que el if sea exitoso, o sea, el usuário (cuyo nombre está en $1) fuera encontrado en /etc/passwd, los comandos del bloque del then serán ejecutados (en este ejemplo es solamente el echo) y en el caso contrario, las instrucciones del bloque del else son las que serán ejecutadas, cuando entonces un nuevo if verifica si el comando useradd fué bien ejecutado , creando el registro del usuario en /etc/passwd, o no cuando entonces dará el mensaje de error.
Veamos su ejecución, primero pasando un usuario ya existente:

$ incusu jneves jneves:x:54002:1001:Julio Neves:/home/jneves:/bin/bash Usuario 'jneves' ya existe

Como ya vimos diversas veces, pero siempre es bueno insistir en el tema para que quedes alertado, en el ejemplo dado surgió una línea no deseada, ella es la salida del comando grep. Para evitar que eso pase, debemos desviar la salida de esta instrucción para /dev/null, quedando así:

$ cat incusu #!/bin/bash # Versión 2 if grep ^$1 /etc/passwd > /dev/null # ou: if grep -q ^$1 /etc/passwd then echo Usuario \'$1\' ya existe else if useradd $1 then echo Usuario \'$1\' incluído en /etc/passwd else echo "Problemas en el catastro. Usted es root?" fi fi

Ahora vamos a verificarlo, pero como usuario normal (no root):

$ incusu JuanNadie ./incusu[6]: useradd: not found Problemas en el catastro. Usted es root?

Epa!, aquél error no era para pasar! Para evitar que eso suceda debemos mandar também la salida de error (strerr, te acuerdas?) del useradd para /dev/null, quedando en la versión final así:

$ cat incusu #!/bin/bash # Versión 3 if grep ^$1 /etc/passwd > /dev/null then echo Usuario \'$1\' ya existe else if useradd $1 2> /dev/null then echo Usuario \'$1\' incluído en /etc/passwd else echo "Problemas en el catastro. Usted es root??" fi fi

Después de estas alteraciones y de hacer un su – (volverme root) veamos su comportamiento:

$ incusu perez Usuario 'perez' incluído en /etc/passwd

Y nuevamente:

$ incusu perez Usuario 'perez' ya existe

Recuerdas que te dije que a lo largo de nuestras conversas y choppes nuestros programas irían a ir mejorando? Entonces veamos ahora como podríamos mejorar nuestro programa para incluir músicas:

$ cat musinc #!/bin/bash # Incluye CDs (versión 3) # if grep "^$1$" musicas > /dev/null then echo Este álbum ya está incluído else echo $1 >> musicas sort musicas -o musicas fi

Como viste, es una pequeña evolución de la versión anterior, de forma que, antes de incluir un registro (que por la versión anterior podría ser duplicado), verificamos si el registro comenzaba (^) y terminaba ($) igual al parámetro pasado ($1). El uso del circunflejo (^) en el inicio de la cadena y el pesos ($) en el fin, son para verificar si el parâmetro pasado (el álbum y sus datos) son exactamente iguales a algún registro anteriormente incluído y no unicamente igual a un pedazo de alguno de los registros.

Vamos a ejecutarlo pasando un álbum ya anteriormente incluído:

$ musinc "album 4^Artista7~Musica7:Artista8~Musica8" Este álbum ya está incluído

Y ahora uno no incluído:

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

     - Como viste, el programa mejoró un poquito, pero todavia no está pronto. A medida que te vaya enseñando a programar en shell, nuestra CDteca va a ir quedando cada vez mejor.

     - Entendí todo lo que me explicaste, pero todavia no sé como hacer un if para verificar condiciones, o sea el uso normal del comando.

     - Mira, para eso existe el comando test, él es el que verifica condiciones. El comando if verifica el comando test. Pero eso está medio confuso y como ya hablé mucho, esty precisando de unos choppes para mojar la palabra. Vamos a parar por aqui y en la próxima vez te explico claramente el uso del test y de diversas otras sintáxis del if.

     - Estamos de acuerdo entonces! Me parece bien porque yo tambiém estoy quedando tonto y así aprovecho para practicar esa cantidad de cosas de las cuales me hablaste hoy .

     - Para fijar lo que aprendiste, trata de hacer un scriptiziño para informar si un determinado usuario, que será pasado como parámetro está logado (ajjjhh!) o no.

     - Chico,dos choppes más por favor...

Y no te olvides, cualquer duda o falta de compañia para tomar 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 - 03 Oct 2006

-- HumbertoPina - 04 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