Difference: TWikiBarConversa008 (1 vs. 9)

Revision 906 Feb 2008 - CollonsTorre

Line: 1 to 1
 

Conversación de bar Parte VIII



     - Hola amigo, como estás?
Changed:
<
<
     - Muy bien!, queria mostrarte lo que hice pero ya sé que tu quieres ir rapido a lo que interesa, no?
>
>
     - Muy bien!, quería mostrarte lo que hice, pero ya sé que tu quieres ir rápido a lo que interesa, no?
 
Changed:
<
<
     - Solo para hacerte la contra, hoy voy a dejar que me muestres tu "programita". Dale, muestrame lo que hiciste.
>
>
     - Solo para llevarte la contraria, hoy voy a dejar que me muestres tu "programita". Venga, muéstrame lo que hiciste.
 
Changed:
<
<
     - Ahhh ... el ejercício que me pasaste es muy extenso. Yo lo resolvi así:
>
>
     - Ahhh ... el ejercicio que me pasaste es muy extenso. Yo lo resolví así:
 
$ cat musinc5 #!/bin/bash
Changed:
<
<
# Catastra CDs (versión 5)
>
>
# Registra CDs (versión 5)
 # clear
Changed:
<
<
LineaMesg=$((`tput lines` - 3)) # Linea que mensajes seran pasados para el operador
>
>
LineaMesg=$((`tput lines` - 3)) # Linea que define cuantos mensajes serán pasados de una vez a la pantalla
 TotCols=$(tput cols) # Cantidad de columnas de la pantalla para encuadrar mensajes echo "   Inclusión de Músicas     ========= == =======    
Changed:
<
<
  Título del Álbun:
>
>
  Título del Álbum:
   | Este campo fue   Pista: < creado solamente para   | orientar como llenar
Line: 35 to 35
 do tput cup 5 38; tput el # Posiciona y limpia linea read Albun
Changed:
<
<
[ ! "$Albun" ] && # Operador dió <ENTER>
>
>
[ ! "$Albun" ] && # Operador pulso <ENTER>
  { Msg="Desea Terminar? (S/n)"         TamMsg=${#Msg}
Line: 50 to 50
  } grep "^$Albun\^" musicas > /dev/null && {
Changed:
<
<
Msg="Este álbun ya está cadastrado"
>
>
Msg="Este álbum ya está incluido"
         TamMsg=${#Msg} Col=$(((TotCols - TamMsg) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col echo "$Msg" read -n1 tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla
Changed:
<
<
continue # Vuelve para leer otro álbun
>
>
continue # Vuelve para leer otro álbum
  } Reg="$Albun^" # $Reg recibirá los datos para grabación elArtista= # Variable que graba artista anterior
Line: 68 to 68
  echo $Track tput cup 9 38 # Posiciona para leer música read Musica
Changed:
<
<
[ "$Musica" ] || # Si el operador dió ...
>
>
[ "$Musica" ] || # Si el operador escribio ...
  {
Changed:
<
<
Msg="Fin del Álbun? (S/n)"
>
>
Msg="Fin del Álbum? (S/n)"
             TamMsg=${#Msg} Col=$(((TotCols - TamMsg) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col
Line: 86 to 86
  read Artista [ "$Artista" ] && elArtista="$Artista" Reg="$Reg$elArtista~$Musica:" # Montando registro
Changed:
<
<
tput cup 9 38; tput el # Borra Musica de la pantalla
>
>
tput cup 9 38; tput el # Borra Música de la pantalla
  tput cup 11 38; tput el # Borra Artista de la pantalla done echo "$Reg" >> musicas # Graba registro en el fin del archivo
Line: 94 to 94
 done
Changed:
<
<
     - Si, el programa esta bien, esta todo bien estructurado, pero me gustaria comentarte un poco lo que hiciste:
>
>
     - Si, el programa esta bien, esta todo bien estructurado, pero me gustaría comentarte un poco lo que hiciste:
 
Changed:
<
<
  • Solo para recordarte, las siguientes construcciones: [ ! $Albun ] && y [ $Musica ] || representan lo mismo, en el primer caso, testamos si la variáble $Album no (!) tiene nada adentro, entonces (&&) ... y en el segundo, testamos lo mismo en $Musica, si no (||) ...
  • Si reclamaste por el tamaño, es porque todavia no te pase algunos trucos. Fijate que la mayor parte del script es para dar mensajes centrados en la penúltima linea de la pantalla. Fijate también que algunos mensajes piden un S o un N y otros son sólo de advertencia. Sería el caso típico del uso de funciones, que serían escritas solamente una vez y llamadas para ejecutar en diversos puntos del script . Voy a hacer dos funciones para resolver estos casos y vamos a incorporarlas a tu programa para ver el resultado final.
>
>
  • Solo para recordarte, las siguientes construcciones: [ ! $Albun ] && y [ $Musica ] || representan lo mismo, en el primer caso, comprobamos si la variable $Album no (!) tiene nada dentro, entonces (&&) ... y en el segundo, comprobamos lo mismo en $Musica, si no (||) ...
  • Si te quejaste por el tamaño, es porque todavía no te pase algunos trucos. Fíjate que la mayor parte del script es para dar mensajes centrados en la penúltima linea de la pantalla. Fíjate también que algunos mensajes piden un S o un N y otros son sólo de advertencia. Sería el caso típico del uso de funciones, que serían escritas solamente una vez y llamadas para ejecutar en diversos puntos del script . Voy a hacer dos funciones para resolver estos casos y vamos a incorporarlas a tu programa para ver el resultado final.
 

Funciones

Changed:
<
<
     - Mozo! Ahora traeme dos chops bien helados, uno sin espuma, para que me de inspiración.
>
>
     - Mozo! Ahora tráeme dos "chops" bien helados, uno sin espuma, para que me de inspiración.
 
    Pregunta ()
        {
Changed:
<
<
# La función recibe 3 parametros en el siguiente orden:
>
>
# La función recibe 3 parámetros en el siguiente orden:
  # $1 - Mensaje que será mostrado en la pantalla
Changed:
<
<
# $2 - Valor que será aceptado como respuesta default
>
>
# $2 - Valor que será aceptado como respuesta por defecto
  # $3 - Otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, la linea a # seguir colocaría en Msg el valor "Acepta? (S/n)"
Line: 119 to 119
  echo "$Msg" tput cup $LineaMesg $((Col + TamMsg? + 1)) read -n1 SN
Changed:
<
<
[ ! $SN ] && SN=$2 # Si vacia coloca default en SN
>
>
[ ! $SN ] && SN=$2 # Si esta vacía coloca por defecto en SN
  echo $SN | tr A-Z a-z # La salida de SN será en minúscula tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla return # Sale de la función }
Changed:
<
<
Como podemos ver, una función es definida cuando hacemos nombre_de_la_función () y todo su cuerpo esta entre llaves ({}). Así como conversamos aqui en el Bar sobre pasar parámetros, las funciones los reciben de la misma forma, o sea, son parámetros de posición ($1, $2, ..., $n) y todas las reglas que se aplican al pase de parámetros para programas, también valen para funciones, pero es muy importante aclarar que los párametros pasados para un programa no se mezclan con aquellos que éste pasó para sus funciones. Esto significa, por ejemplo, que el $1 de un script es diferente del $1 de una de sus funciones.
>
>
Como podemos ver, una función es definida cuando hacemos nombre_de_la_función () y todo su cuerpo esta entre llaves ({}). Así como charlamos aquí en el Bar sobre pasar parámetros, las funciones los reciben de la misma forma, o sea, son parámetros de posición ($1, $2, ..., $n) y todas las reglas que se aplican al pase de parámetros para programas, también valen para funciones, pero es muy importante aclarar que los parámetros pasados hacia un programa no se mezclan con aquellos que éste pasó hacia sus funciones. Esto significa, por ejemplo, que el $1 de un script es diferente del $1 de una de sus funciones.
 
Changed:
<
<
Fíjate que las variables $Msg, $TamMsg y $Col son de uso restricto de esta rutina, y por eso fueron creadas como local. La finalidad de esto es simplemente economizar memória, ya que al salir de la rutina, ellas serán destruidas de la partición y si por acaso no tuviese usado este artifício, estarian residentes en la memória.
>
>
Fíjate que las variables $Msg, $TamMsg y $Col son de uso restringido de esta rutina, y por eso fueron creadas como local. La finalidad de esto es simplemente economizar memoria, ya que al salir de la rutina, todas serán destruidas y si no hubiese usado esta opción, se quedarían residentes en la memoria.
 
Changed:
<
<
La linea de código que crea local Msg, junta el texto recibido ($1) abre parentesis, la respuesta default ($2) en mayuscula, una barra, la otra respuesta ($3) en minúscula y finaliza cerrando el paréntesis. Uso esta forma para, que al mismo tiempo, pueda mostrar las opciones disponibles y destacar la respuesta ofrecida como default.
>
>
La linea de código que crea local Msg, junta el texto recibido ($1) abre paréntesis, la respuesta default ($2) en mayúscula, una barra, la otra respuesta ($3) en minúscula y finaliza cerrando el paréntesis. Uso esta forma para, que al mismo tiempo, pueda mostrar las opciones disponibles y destacar la respuesta ofrecida como default.
 
Changed:
<
<
Casi al fin de la rutina, la respuesta recibida ($SN) es pasada para minuscula de forma que en el cuerpo del programa no se necesite hacer esta prueba.
>
>
Casi al final de la rutina, la respuesta recibida ($SN) se pasa a minúscula de forma que en el cuerpo del programa no se necesite hacer esta prueba.
 
Changed:
<
<
Veamos ahora como quedaria la función para dar un mensaje en la pantalla:
>
>
Veamos ahora como quedaría la función para presentar un mensaje en la pantalla:
 
    function MandaMsg
Line: 143 to 143
  # con el mensaje que se desea mostrar, # para no obligar al programador que pase # el mensaje entre comillas, usaremos $* (todos
Changed:
<
<
# los parametros, te acuerdas?) y no $1.
>
>
# los parámetros, te acuerdas?) y no $1.
  local Msg="$*" local TamMsg?=${#Msg} local Col=$(((TotCols? - TamMsg?) / 2)) # Centra el mensaje en la linea
Line: 155 to 155
  }
Changed:
<
<
Esta es otra forma de definir una función: no la llamamos como en el ejemplo anterior usando una construcción con la sintaxis nombre_de_la_función (), sino como function nombre_de_la_función. No tiene ninguna diferencia con la anterior, excepto que, como consta en los comentários, usamos la variable $* que como ya sabemos es el conjunto de todos los parametros pasados, para que el programador no necesite usar comillas envolviendo el mensaje que desea pasar para la función.
>
>
Esta es otra forma de definir una función: no la llamamos como en el ejemplo anterior usando una construcción con la sintaxis nombre_de_la_función (), sino como function nombre_de_la_función. No tiene ninguna diferencia con la anterior, excepto que, como consta en los comentarios, usamos la variable $* que como ya sabemos es el conjunto de todos los parámetros pasados, para que el programador no necesite usar comillas envolviendo el mensaje que desea pasar para la función.
  Para terminar con este blá-blá-blá vamos a ver entonces las alteraciones que el programa necesita cuando usamos el concepto de funciones:

$ cat musinc6 #!/bin/bash
Changed:
<
<
# Cadastra CDs (versión 6)
>
>
# Registra CDs (versión 6)
 #

# Área de las variables globales

Line: 273 to 273
 
  Cuerpo del Programa  
Changed:
<
<
Esta estruturación es debido a que el Shell es un lenguaje interpretado y así el programa es leído de izquierda a derecha y de arriba para abajo. De esa forma, una variable para ser vista simultáneamente por el script y sus funciones, debe ser declarada (o inicializada) antes de cualquier otra cosa. Las funciones deben ser declaradas antes del cuerpo del programa propiamente dicho porque en el lugar en que el programador mencionó su nombre, el interpretador Shell ya lo habia localizado antes y registrado que era una función.
>
>
Esta estructuración es debida a que el Shell es un lenguaje interpretado y así el programa es leído de izquierda a derecha y de arriba para abajo. De esa forma, para que una variable sea vista simultáneamente por el script y sus funciones, debe ser declarada (o inicializada) antes de cualquier otra cosa. Las funciones deben ser declaradas antes del cuerpo del programa propiamente dicho para que en el lugar en que el programador mencione su nombre, el interprete Shell ya lo haya localizado antes y registrado que es una función.
 
Changed:
<
<
Una cosa muy útil en el uso de funciones es tratar de hacerlas lo más generales posible, de forma que sirvan para otras aplicaciones, sin necesidad de tener que reescribirlas. Esas dos que acabamos de ver tienen uso general, pues es dificil hallar un script que tenga una entrada de datos por teclado que no use una rutina del tipo de la MandaMsg o no interaccione con el operador a través de algo parecido a Pergunta.
>
>
Una cosa muy útil en el uso de funciones es tratar de hacerlas lo más generales posible, de forma que sirvan para otras aplicaciones, sin necesidad de tener que reescribirlas. Esas dos que acabamos de ver tienen uso general, pues es dificil hallar un script que tenga una entrada de datos por teclado que no use una rutina del tipo de la MandaMsg o no interaccione con el operador a través de algo parecido a Pregunta.
 
Changed:
<
<
Consejo de amigo: crie un archivo y cada función nueva que programes, anéxela a este archivo. Al final de un tiempo tendrás una bella biblioteca de funciones que te ahorrará mucho tiempo de programación.
>
>
Consejo de amigo: crea un archivo y cada función nueva que programes, añádela a este archivo. Así con el tiempo tendrás una bella biblioteca de funciones que te ahorrará mucho tiempo de programación.
 

El comando source

Changed:
<
<
Vé si tu notas algo diferente en la salida del ls siguiente:
>
>
Fíjate si notas algo diferente en la salida del ls siguiente:
 
$ ls -la .bash_profile -rw-r--r-- 1 Julio unknown 4511 Mar 18 17:45 .bash_profile
Changed:
<
<
No mires la respuesta y vuelve a dar atención! Bien, ya que estás sin paciencia para pensar y prefieres leer la respuesta, te voy a dar una pista: me pareces que sabes que el .bash_profile es uno de los programas que son automáticamente "ejecutados" cuando tu te logas (ARRGGHH! Odeo este término). Ahora que te dí esta ayuda, mira nuevamente la salida del ls y dime que hay de diferente en ella.
>
>
No mires la respuesta y vuelve a prestar atención! De acuerdo, ya que no tienes paciencia para pensar y prefieres leer la respuesta, te voy a dar una pista: me parece que ya sabes que el .bash_profile es uno de los programas que son automáticamente "ejecutados" cuando tu te logeas (ARRGGHH! Odio este término). Ahora que te dí esta ayuda, mira nuevamente la salida del ls y dime que hay de diferente en ella.
 
Changed:
<
<
Como te dije el .bash_profile es "ejecutado" en el momento del logon y nota que no tiene ningúna prerrogativa de ejecución. Esto se dá porque si tu lo ejecutaras como cualquier otro script simple, cuando su ejecución terminara, todo el ambiente generado por él morrería junto con el Shell en el cual fue ejecutado (te acuerdas que todos los scripts son ejecutados en subshells, verdad?).
>
>
Como te dije el .bash_profile es "ejecutado" en el momento del logon y fíjate que no tiene ningúna prerrogativa de ejecución. Esto ocurre porque si tu lo ejecutaras como cualquier otro script simple, cuando terminara su ejecución, todo el ambiente generado por él moriría junto con el Shell en el cual fue ejecutado (te acuerdas que todos los scripts son ejecutados en subshells, verdad?).
 
Changed:
<
<
Pues bien, es para cosas así que existe el comando source, tambiém conocido por . (punto). Este comando hace que no sea creado un nuevo Shell (un subshell) para ejecutar el programa que le es pasado como parámetro.
>
>
Pues bien, es para cosas así que existe el comando source, también conocido por . (punto). Este comando hace que no sea creado un nuevo Shell (un subshell) para ejecutar el programa que le es pasado como parámetro.
 
Changed:
<
<
Mejor um ejemplo que 10.000 palabras. Mira este scriptiziño que sigue:
>
>
Mejor un ejemplo que 10.000 palabras. Mira el scriptiziño siguiente:
 
$ cat script_bobo
Line: 302 to 302
 ls
Changed:
<
<
Él simplemente debería ir para el directório arriba del directório actual. Vamos a ejecutar unos comandos que incluyen el script_bobo y vamos a analizar los resultados:
>
>
Simplemente debería ir hacia el directório superior del directório actual. Vamos a ejecutar unos comandos que incluyen el script_bobo y vamos a analizar los resultados:
 
$ pwd
Line: 313 to 313
 /home/jneves
Changed:
<
<
Si yo mandé subir un directório, porque no subió? Subió sí! El subshell que fue creado para ejecutar el script subió y listó los directórios de los cuatro usuarios abajo del /home, solo que así como el script acabó, el subshell fue para el limbo y con él, todo el ambiente creado. Mira ahora como la cosa cambia:
>
>
Si yo mandé subir un directório, porque no subió? Subió sí! El subshell que fue creado para ejecutar el script subió y listó los directórios de los cuatro usuarios debajo del /home, solo que así que el script acabó, el subshell se fue al limbo y con él, todo el ambiente creado. Mira ahora como la cosa cambia:
 
$ source script_bobo
Line: 328 to 328
 /home
Changed:
<
<
Ahh! Ahora sí! Siendo pasado como parámetro del comando source o . (punto), el script fue ejecutado en el Shell corriente dejando en este, todo el ambiente creado. Ahora damos un rewind para el inicio de la explicación sobre este comando. Allá atrás, hablamos del .bash_profile, y a esta altura ya debes saber que su tarea es, enseguida del login, dejar el ambiente de trabajo preparado para el usuário, y ahora entendemos que es por eso mismo que el es ejecutado usando este artifício.
>
>
Ahh! Ahora sí! Siendo pasado como parámetro del comando source o . (punto), el script fue ejecutado en el Shell corriente dejando en este, todo el ambiente creado. Ahora damos un rewind hacia el inicio de la explicación sobre este comando. Un poco antes, hablamos del .bash_profile, y a estas alturas ya debes saber que su tarea es, inmediatamente después del login, dejar el ambiente de trabajo preparado para el usuário, y ahora entendemos que por eso es ejecutado usando esta construcción.
 
Changed:
<
<
Y ahora debes estarte preguntando si es sólo para eso que este comando sirve, y yo te digo que sí, pero eso nos trae una cantidad de ventajas y una de las más usadas es tratar funciones como rutinas externas. Vé una forma diferente de hacer nuestro programa para incluir CDs en el archivo musicas:
>
>
Y ahora debes estarte preguntando, sólo sirve para eso este comando?, y yo te digo que sí, pero eso nos trae una cantidad de ventajas y una de las más usadas es tratar funciones como rutinas externas. Mira una forma diferente de hacer nuestro programa para incluir CDs en el archivo musicas:
 
$ cat musinc7 #!/bin/bash
Changed:
<
<
# Cadastra CDs (versión7)
>
>
# Registra CDs (versión7)
 #

# Área de varibles globales

Line: 399 to 399
 done
Changed:
<
<
Ahora el programa dió una buena disminuída de tamaño y las llamadas de función fueron cambiadas por archivos externos llamados pergunta.func y mandamsg.func, que de esta forma, pueden ser llamados por cualquer otro programa y com eso, reutilizando su código.
>
>
Ahora el programa disminuyo considerablemente de tamaño y las funciones fueron cambiadas por archivos externos llamados pergunta.func y mandamsg.func, que de esta forma, pueden ser llamados por cualquer otro programa y con eso, reutilizando su código.
 
Changed:
<
<
Por motivos meramente didácticos las ejecuciones de pergunta.func y mandamsg.func están siendo comandadas por source y por . (ponto) indiscriminadamente, sin embargo, prefiera el source por ser más visible lo que dá mayor legibilidad al código y facilita su manutención posteriormente.
>
>
Por motivos meramente didácticos las ejecuciones de pergunta.func y mandamsg.func están siendo llamadas por source y por . (punto) indiscriminadamente, sin embargo, prefiero el source por ser más visible, lo que le da mayor legibilidad al código y facilita su manutención posteriormente.
 
Changed:
<
<
Vea ahora como quedaron estes dos archivos:
>
>
Mira ahora como quedaron estos dos archivos:
 
$ cat pergunta.func # La función recibe 3 parámetros en el siguiente orden:
Changed:
<
<
# $1 - Mensaje a ser dada en la pantalla # $2 - Valor a ser aceptado como respuesta default
>
>
# $1 - Mensaje a ser enviado a la pantalla # $2 - Valor que sera aceptado como respuesta por defecto
 # $3 - El otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, en la línea
Changed:
<
<
# abajo colocaría en Msg el valor "Acepta? (s/n)"
>
>
# de abajo colocaría en Msg el valor "Acepta? (s/n)"
 Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" TamMsg=${#Msg}
Changed:
<
<
Col=$(((TotCols - TamMsg) / 2)) # Centraliza msg en la línea
>
>
Col=$(((TotCols - TamMsg) / 2)) # Centra msg en la línea
 tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + TamMsg + 1)) read -n1 SN
Changed:
<
<
[ ! $SN ] && SN=$2 # Si vacía coloca default en SN
>
>
[ ! $SN ] && SN=$2 # Si esta vacía coloca default en SN
 echo $SN | tr A-Z a-z # La salida de SN será en minúscula tput cup $LinhaMesg $Col; tput el # Borra msg de la pantalla $ cat mandamsg.func # La función recibe solamente un parámetro # con el mensaje que se desea exhibir, # para no obligar al programador a pasar
Changed:
<
<
# el msq entre comillas, usaremos $* (todos
>
>
# el msg entre comillas, usaremos $* (todos
 # los parámetro, recuerdas?) y no $1. Msg="$*" TamMsg=${#Msg}
Line: 441 to 441
 En ambos archivos, hice solamente dos cambios que veremos en las observaciones que siguen, sin embargo tengo tres observaciones más para hacer:

  1. Las variables no están siendo declaradas como local, porque está es una directiva que solamente puede ser usada en el cuerpo de funciones y por consiguiente, estas variables permanecen en el ambiente del Shell, llenándolo de basura;
Changed:
<
<
  1. El comando return no está presente pero podería estar, sin alterar en nada la lógica, una vez que él sólo serviría para indicar un eventual error vía un código de retorno previamente establecido (por ejemplo return 1, return 2, ...), siendo que el return y return 0 son idénticos y significan rutina ejecutada sin errores;
>
>
  1. El comando return no está presente pero podría estarlo, sin alterar en nada la lógica, ya que sólo serviría para indicar un eventual error vía un código de retorno previamente establecido (por ejemplo return 1, return 2, ...), siendo que el return y return 0 son idénticos y significan rutina ejecutada sin errores;
 
  1. El comando que estamos acostumbrados a usar para generar código de retorno es el exit, pero la salida de una rutina externa no puede ser hecha de esta forma, porque por estar siendo ejecutada en el mismo Shell que el script llamador, el exit simplemente cerraría este Shell, terminando la ejecución de todo el script;
Changed:
<
<
  1. De donde surgió la variable LinhaMesg? Ella vino del musinc7, porque habia sido declarada antes de la llamada de las rutinas (sin olvidar que el Shell que está interpretando el script y estas rotinas, es el mismo para todos);
  2. Si decidiste usar rutinas externas, no seas haragán, abunda en los comentarios (principalmente sobre el pasaje de los parámetros) para facilitar la manutención y su uso por otros programas en el futuro.
>
>
  1. De donde surgió la variable LinhaMesg? Ella vino del musinc7, porque habia sido declarada antes de la llamada de las rutinas (sin olvidar que el Shell que está interpretando el script y estas rutinas, es el mismo para todos);
  2. Si decidiste usar rutinas externas, no seas haragán, abunda en los comentarios (principalmente sobre el pasaje de los parámetros) para facilitar la manutención y su uso para otros programas en el futuro.
       - Bien, ahora ya tienes una cantidad de novedades para mejorar los scripts que hicimos. Te acuerdas del programa listartista en el cual pasabas el nombre de un artista como parámetro y él devolvia sus músicas? Era así:
Line: 470 to 470
       - Claro que me acuerdo!...
Changed:
<
<
     - Entonces para afirmar los conceptos que te pasé, hazlo con la pantalla formatada, en loop, de forma que solamente termine cuando reciba un <ENTER> puro en el nombre del artista. Ahhh! Cuando la lista llegue a la antepenúltima línea de la pantalla, el programa deberá dar una parada para que el operador pueda leerlas, o sea, suponga que la pantalla tenga 25 linhas. A cada 22 músicas listadas (cantidad de líneas menos 3) el programa aguardará a que el operador teclee algo para entonces continuar. Eventuales mensajes de error deben ser pasados usando la rutina mandamsg.func que acabamos de hacer.
>
>
     - Entonces para afirmar los conceptos que te pasé, hazlo con la pantalla formateada, en loop, de forma que solamente termine cuando reciba un <ENTER> puro en el nombre del artista. Ahhh! Cuando la lista llegue a la antepenúltima línea de la pantalla, el programa deberá detenerse para que el operador pueda leerlas, o sea, imagina que la pantalla tenga 25 lineas. Cada 22 músicas listadas (cantidad de líneas menos 3) el programa aguardará a que el operador teclee algo para entonces continuar. Eventuales mensajes de error deben ser pasados usando la rutina mandamsg.func que acabamos de hacer.
       - Mozo, trae dos más, el mio con poca presión...
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 803 Feb 2008 - JulioNeves

Line: 1 to 1
Changed:
<
<

Conversa de bar Parte VIII

>
>

Conversación de bar Parte VIII

 


Revision 731 May 2007 - JulioNeves

Line: 1 to 1
 

Conversa de bar Parte VIII


Line: 418 to 418
 Col=$(((TotCols - TamMsg) / 2)) # Centraliza msg en la línea tput cup $LinhaMesg $Col echo "$Msg"
Changed:
<
<
tput cup $LinhaMesg $((Col + zTamMsg + 1))
>
>
tput cup $LinhaMesg $((Col + TamMsg + 1))
 read -n1 SN [ ! $SN ] && SN=$2 # Si vacía coloca default en SN echo $SN | tr A-Z a-z # La salida de SN será en minúscula

Revision 613 Feb 2007 - JulioNeves

Line: 1 to 1
 

Conversa de bar Parte VIII


Line: 476 to 476
  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 - 10 Jan 2007

Revision 510 Jan 2007 - Main.HumbertoPina

Line: 1 to 1
 

Conversa de bar Parte VIII


Line: 14 to 14
 
$ cat musinc5 #!/bin/bash
Changed:
<
<
# Cadastra CDs (versión 5)
>
>
# Catastra CDs (versión 5)
 # clear LineaMesg=$((`tput lines` - 3)) # Linea que mensajes seran pasados para el operador
Line: 26 to 26
     Título del Álbun:   | Este campo fue
Changed:
<
<
  Track: < creado solamente para
>
>
  Pista: < creado solamente para
   | orientar como llenar   Nombre de la Música:  
Line: 216 to 216
     Título del Álbun:   | Este campo fue
Changed:
<
<
  Track: < creado solamente para
>
>
  Pista: < creado solamente para
   | orientar como llenar   Nombre de la Música:  
Line: 228 to 228
  [ ! "$Albun" ] && # Operador dió { Pregunta "Desea Terminar" s n
Changed:
<
<
[ $SN = "n" ] && continue # Ahora sólo prueba la minúscula
>
>
[ $SN = "n" ] && continue # Ahora sólo verifico minúsculas
  clear; exit # Fin de la ejecución } grep -iq "^$Albun\^" musicas 2> /dev/null &&
Line: 273 to 273
 
  Cuerpo del Programa  
Changed:
<
<
Esta estruturação es debido a que el Shell es un lenguaje interpretado y así el programa es leído de izquierda a derecha y de arriba para abajo y una variable para ser vista simultáneamente por el script y sus funciones debe ser declarada (o inicializada) antes de cualquier cosa. Las funciones deben ser declaradas antes del cuerpo del programa propriamente dicho porque en el lugar en que el programador mencionó su nombre, el interpretador Shell ya lo habia localizado antes y registrado que era una función.
>
>
Esta estruturación es debido a que el Shell es un lenguaje interpretado y así el programa es leído de izquierda a derecha y de arriba para abajo. De esa forma, una variable para ser vista simultáneamente por el script y sus funciones, debe ser declarada (o inicializada) antes de cualquier otra cosa. Las funciones deben ser declaradas antes del cuerpo del programa propiamente dicho porque en el lugar en que el programador mencionó su nombre, el interpretador Shell ya lo habia localizado antes y registrado que era una función.
 
Changed:
<
<
Una cosa muy buena enel uso de funciones es hacerlas lo más generales posibles de forma que sirvan para otras aplicaciones, sin necesidad de tener que reescribirlas. Esas dos que acabamos de ver tiene uso general, pues es dificil hallar un script que tenga una entrada de datos por teclado que no use una rutina del tipo de la MandaMsg o no interacciona con el operador a través de algo parecido a Pergunta.
>
>
Una cosa muy útil en el uso de funciones es tratar de hacerlas lo más generales posible, de forma que sirvan para otras aplicaciones, sin necesidad de tener que reescribirlas. Esas dos que acabamos de ver tienen uso general, pues es dificil hallar un script que tenga una entrada de datos por teclado que no use una rutina del tipo de la MandaMsg o no interaccione con el operador a través de algo parecido a Pergunta.
 
Changed:
<
<
Consejo de amigo: crie un archivo y cada función nueva que críes, anéxela a este archivo. Al final de un tiempo tendrás una bella biblioteca de funciones que te ahorrará mucho tiempo de programación.
>
>
Consejo de amigo: crie un archivo y cada función nueva que programes, anéxela a este archivo. Al final de un tiempo tendrás una bella biblioteca de funciones que te ahorrará mucho tiempo de programación.
 
Changed:
<
<

O comando source

>
>

El comando source

 
Changed:
<
<
Vê se você nota algo de diferente na saída do ls a seguir:
>
>
Vé si tu notas algo diferente en la salida del ls siguiente:
 
$ ls -la .bash_profile -rw-r--r-- 1 Julio unknown 4511 Mar 18 17:45 .bash_profile
Changed:
<
<
Não olhe a resposta não, volte a prestar atenção! Bem, já que você está mesmo sem saco de pensar e prefere ler a resposta, vou te dar uma dica: acho que você sabe que o .bash_profile é um dos programas que são automaticamente "executados" quando você se loga (ARRGGHH! Odeio este termo). Agora que te dei esta dica olhe novamente para a saída do ls e me diga o que há de diferente nela.
>
>
No mires la respuesta y vuelve a dar atención! Bien, ya que estás sin paciencia para pensar y prefieres leer la respuesta, te voy a dar una pista: me pareces que sabes que el .bash_profile es uno de los programas que son automáticamente "ejecutados" cuando tu te logas (ARRGGHH! Odeo este término). Ahora que te dí esta ayuda, mira nuevamente la salida del ls y dime que hay de diferente en ella.
 
Changed:
<
<
Como eu disse o .bash_profile é "executado" em tempo de logon e repare que não tem nenhum direito de execução. Isso se dá porque o se você o executasse como qualquer outro script careta, quando terminasse sua execução todo o ambiente por ele gerado morreria junto com o Shell sob o qual ele foi executado (você se lembra que todos os scripts são executados em subshells, né?).
>
>
Como te dije el .bash_profile es "ejecutado" en el momento del logon y nota que no tiene ningúna prerrogativa de ejecución. Esto se dá porque si tu lo ejecutaras como cualquier otro script simple, cuando su ejecución terminara, todo el ambiente generado por él morrería junto con el Shell en el cual fue ejecutado (te acuerdas que todos los scripts son ejecutados en subshells, verdad?).
 
Changed:
<
<
Pois é. É para coisas assim que existe o comando source, também conhecido por . (ponto). Este comando faz com que não seja criado um novo Shell (um subshell) para executar o programa que que lhe é passado como parâmetro.
>
>
Pues bien, es para cosas así que existe el comando source, tambiém conocido por . (punto). Este comando hace que no sea creado un nuevo Shell (un subshell) para ejecutar el programa que le es pasado como parámetro.
 
Changed:
<
<
Melhor um exemplo que 453 palavras. Veja este scriptizinho a seguir:
>
>
Mejor um ejemplo que 10.000 palabras. Mira este scriptiziño que sigue:
 
$ cat script_bobo
Line: 302 to 302
 ls
Changed:
<
<
Ele simplesmente deveria ir para o diretório acima do diretório atual. Vamos executar uns comandos envolvendo o script_bobo e vamos analisar os resultados:
>
>
Él simplemente debería ir para el directório arriba del directório actual. Vamos a ejecutar unos comandos que incluyen el script_bobo y vamos a analizar los resultados:
 
$ pwd
Line: 313 to 313
 /home/jneves
Changed:
<
<
Se eu mandei ele subir um diretório, porque não subiu? Subiu sim! O subshell que foi criado para executar o script tanto subiu que listou os diretórios dos quatro usuários abaixo do /home, só que assim que o script acabou, o subshell foi para o beleleu e com ele todo o ambiente criado. Olha agora como a coisa muda:
>
>
Si yo mandé subir un directório, porque no subió? Subió sí! El subshell que fue creado para ejecutar el script subió y listó los directórios de los cuatro usuarios abajo del /home, solo que así como el script acabó, el subshell fue para el limbo y con él, todo el ambiente creado. Mira ahora como la cosa cambia:
 
$ source script_bobo
Line: 328 to 328
 /home
Changed:
<
<
Ahh! Agora sim! Sendo passado como parâmetro do comando source ou . (ponto), o script foi executado no Shell corrente deixando neste, todo o ambiente criado. Agora damos um rewind para o início da explicação sobre este comando. Lá falamos do .bash_profile, e a esta altura você já deve saber que a sua incumbência é, logo após o login, deixar o ambiente de trabalho preparado para o usuário, e agora entendemos que é por isso mesmo que ele é executado usando este artifício.
>
>
Ahh! Ahora sí! Siendo pasado como parámetro del comando source o . (punto), el script fue ejecutado en el Shell corriente dejando en este, todo el ambiente creado. Ahora damos un rewind para el inicio de la explicación sobre este comando. Allá atrás, hablamos del .bash_profile, y a esta altura ya debes saber que su tarea es, enseguida del login, dejar el ambiente de trabajo preparado para el usuário, y ahora entendemos que es por eso mismo que el es ejecutado usando este artifício.
 
Changed:
<
<
E agora você deve estar se perguntando se é só para isso que este comando serve, e eu lhe digo que sim, mas isso nos traz um monte de vantagens e uma das mais usadas é tratar funções como rotinas externas. Veja uma outra forma de fazer o nosso programa para incluir CDs no arquivo musicas:
>
>
Y ahora debes estarte preguntando si es sólo para eso que este comando sirve, y yo te digo que sí, pero eso nos trae una cantidad de ventajas y una de las más usadas es tratar funciones como rutinas externas. Vé una forma diferente de hacer nuestro programa para incluir CDs en el archivo musicas:
 
$ cat musinc7 #!/bin/bash
Changed:
<
<
# Cadastra CDs (versao 7)
>
>
# Cadastra CDs (versión7)
 #
Changed:
<
<
# Área de variáveis globais LinhaMesg=$((`tput lines` - 3)) # Linha que msgs serão dadas para operador TotCols=$(tput cols) # Qtd colunas da tela para enquadrar msgs
>
>
# Área de varibles globales LinhaMesg=$((`tput lines` - 3)) # Línea que msgs serán dadas para operador TotCols=$(tput cols) # Qtd colunas de la tela para encuadrar msgs
 
Changed:
<
<
# O corpo do programa propriamente dito começa aqui
>
>
# El cuerpo del programa propriamente dicho comienza aqui
 clear echo "
Changed:
<
<
Inclusao de Músicas
>
>
Inclusión de Músicas
     ======== == =======       Título do Álbum:
Changed:
<
<
  | Este campo foi   Faixa: < criado somente para   | orientar o preenchimento   Nome da Música:
>
>
  | Este campo fue   Pista: < creado solamente para   | orientar como llenar   Nombre de la Música:
  
Changed:
<
<
  Intérprete:" # Tela montada com um único echo
>
>
  Intérprete:" # Pantalla montada con un único echo
 while true do
Changed:
<
<
tput cup 5 38; tput el # Posiciona e limpa linha
>
>
tput cup 5 38; tput el # Posiciona y limpa línea
  read Album
Changed:
<
<
[ ! "$Album" ] && # Operador deu
>
>
[ ! "$Album" ] && # Operador dió
  {
Changed:
<
<
source pergunta.func "Deseja Terminar" s n [ $SN = "n" ] && continue # Agora só testo a caixa baixa clear; exit # Fim da execução
>
>
source pergunta.func "Desea Terminar" s n [ $SN = "n" ] && continue # Ahora sólo verifico minúsculas clear; exit # Fin de la ejecución
  } grep -iq "^$Album\^" musicas 2> /dev/null && {
Changed:
<
<
. mandamsg.func Este álbum já está cadastrado continue # Volta para ler outro álbum
>
>
. mandamsg.func Este álbum ya está catastrado continue # Vuelve para leer otro álbum
  }
Changed:
<
<
Reg="$Album^" # $Reg receberá os dados de gravação
>
>
Reg="$Album^" # $Reg reciberá los datos de grabación
  oArtista= # Guardará artista anterior while true do ((Faixa++)) tput cup 7 38 echo $Faixa
Changed:
<
<
tput cup 9 38 # Posiciona para ler musica
>
>
tput cup 9 38 # Posiciona para leer música
  read Musica
Changed:
<
<
[ "$Musica" ] || # Se o operador tiver dado ...
>
>
[ "$Musica" ] || # Si el operador hubiese dado ...
  {
Changed:
<
<
. pergunta.func "Fim de Álbum?" s n [ "$SN" = n ] && continue # Agora só testo a caixa baixa break # Sai do loop para gravar dados
>
>
. pergunta.func "Fin del Álbum?" s n [ "$SN" = n ] && continue # Ahora sólo verifico minúsculas break # Sale del loop para grabar datos
  }
Changed:
<
<
tput cup 11 38 # Posiciona para ler Artista
>
>
tput cup 11 38 # Posiciona para leer Artista
  [ "$oArtista" ] && echo -n "($oArtista) " # Artista anter. é default read Artista [ "$Artista" ] && oArtista="$Artista" Reg="$Reg$oArtista~$Musica:" # Montando registro
Changed:
<
<
tput cup 9 38; tput el # Apaga Musica da tela tput cup 11 38; tput el # Apaga Artista da tela
>
>
tput cup 9 38; tput el # Borra Musica de la pantalla tput cup 11 38; tput el # Borra Artista de la pantalla
  done
Changed:
<
<
echo "$Reg" >> musicas # Grava registro no fim do arquivo sort musicas -o musicas # Classifica o arquivo
>
>
echo "$Reg" >> musicas # Graba registro en el fin del archivo sort musicas -o musicas # Clasifica el archivo
 done
Changed:
<
<
Agora o programa deu uma boa encolhida e as chamadas de função foram trocadas por arquivos externos chamados pergunta.func e mandamsg.func, que assim podem ser chamados por qualquer outro programa, desta forma reutilizando o seu código.
>
>
Ahora el programa dió una buena disminuída de tamaño y las llamadas de función fueron cambiadas por archivos externos llamados pergunta.func y mandamsg.func, que de esta forma, pueden ser llamados por cualquer otro programa y com eso, reutilizando su código.
 
Changed:
<
<
Por motivos meramente didáticos as execuções de pergunta.func e mandamsg.func estão sendo comandadas por source e por . (ponto) indiscriminadamente, embora prefira o source por ser mais visível desta forma dando maior legibilidade ao código e facilitando sua posterior manutenção.
>
>
Por motivos meramente didácticos las ejecuciones de pergunta.func y mandamsg.func están siendo comandadas por source y por . (ponto) indiscriminadamente, sin embargo, prefiera el source por ser más visible lo que dá mayor legibilidad al código y facilita su manutención posteriormente.
 
Changed:
<
<
Veja agora como ficaram estes dois arquivos:
>
>
Vea ahora como quedaron estes dos archivos:
 
$ cat pergunta.func
Changed:
<
<
# A função recebe 3 parâmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default # $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha # abaixo colocaria em Msg o valor "Aceita? (S/n)"
>
>
# La función recibe 3 parámetros en el siguiente orden: # $1 - Mensaje a ser dada en la pantalla # $2 - Valor a ser aceptado como respuesta default # $3 - El otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, en la línea # abajo colocaría en Msg el valor "Acepta? (s/n)"
 Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" TamMsg=${#Msg}
Changed:
<
<
Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha
>
>
Col=$(((TotCols - TamMsg) / 2)) # Centraliza msg en la línea
 tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + zTamMsg + 1)) read -n1 SN
Changed:
<
<
[ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A saída de SN será em minúscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela
>
>
[ ! $SN ] && SN=$2 # Si vacía coloca default en SN echo $SN | tr A-Z a-z # La salida de SN será en minúscula tput cup $LinhaMesg $Col; tput el # Borra msg de la pantalla
 $ cat mandamsg.func
Changed:
<
<
# A função recebe somente um parâmetro # com a mensagem que se deseja exibir, # para não obrigar ao programador passar # a msq entre aspas, usaremos $* (todos # os parâmetro, lembra?) e não $1.
>
>
# La función recibe solamente un parámetro # con el mensaje que se desea exhibir, # para no obligar al programador a pasar # el msq entre comillas, usaremos $* (todos # los parámetro, recuerdas?) y no $1.
 Msg="$*" TamMsg=${#Msg}
Changed:
<
<
Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha
>
>
Col=$(((TotCols - TamMsg) / 2)) # Centra msg en la línea
 tput cup $LinhaMesg $Col echo "$Msg" read -n1
Changed:
<
<
tput cup $LinhaMesg $Col; tput el # Apaga msg da tela
>
>
tput cup $LinhaMesg $Col; tput el # Borra msg de la pantalla
 
Changed:
<
<
Em ambos os arquivos, fiz somente duas mudanças que veremos nas observações a seguir, porém tenho mais três a fazer:
>
>
En ambos archivos, hice solamente dos cambios que veremos en las observaciones que siguen, sin embargo tengo tres observaciones más para hacer:
 
Changed:
<
<
  1. As variáveis não estão sendo mais declaradas como local, porque está é uma diretiva que só pode ser usada no corpo de funções e portanto estas variáveis permanecem no ambiente do Shell, poluindo-o;
  2. O comando return não está mais presente mas poderia estar sem alterar em nada a lógica, uma vez que ele só serviria para indicar um eventual erro via um código de retorno previamente estabelecido (por exemplo return 1, return 2, ...), sendo que o return e return 0 são idênticos e significam rotina executada sem erros;
  3. O comando que estamos acostumados a usar para gerar código de retorno é o exit, mas a saída de uma rotina externa não pode ser feita desta forma, porque por estar sendo executada no mesmo Shell que o script chamador, o exit simplesmente encerraria este Shell, terminando a execução de todo o script;
  4. De onde surgiu a variável LinhaMesg? Ela veio do musinc7, porque ela havia sido declarada antes da chamada das rotinas (nunca esquecendo que o Shell que está interpretando o script e estas rotinas é o mesmo);
  5. Se você decidir usar rotinas externas, não se avexe, abunde os comentários (principalmente sobre a passagem dos parâmetros) para facilitar a manutenção e seu uso por outros programas no futuro.
>
>
  1. Las variables no están siendo declaradas como local, porque está es una directiva que solamente puede ser usada en el cuerpo de funciones y por consiguiente, estas variables permanecen en el ambiente del Shell, llenándolo de basura;
  2. El comando return no está presente pero podería estar, sin alterar en nada la lógica, una vez que él sólo serviría para indicar un eventual error vía un código de retorno previamente establecido (por ejemplo return 1, return 2, ...), siendo que el return y return 0 son idénticos y significan rutina ejecutada sin errores;
  3. El comando que estamos acostumbrados a usar para generar código de retorno es el exit, pero la salida de una rutina externa no puede ser hecha de esta forma, porque por estar siendo ejecutada en el mismo Shell que el script llamador, el exit simplemente cerraría este Shell, terminando la ejecución de todo el script;
  4. De donde surgió la variable LinhaMesg? Ella vino del musinc7, porque habia sido declarada antes de la llamada de las rutinas (sin olvidar que el Shell que está interpretando el script y estas rotinas, es el mismo para todos);
  5. Si decidiste usar rutinas externas, no seas haragán, abunda en los comentarios (principalmente sobre el pasaje de los parámetros) para facilitar la manutención y su uso por otros programas en el futuro.
 
Changed:
<
<
     - Bem, agora você já tem mais um monte de novidade para melhorar os scripts que fizemos você se lembra do programa listartista no qual você passava o nome de um artista como parâmetro e ele devolvia as suas músicas? Ele era assim:
>
>
     - Bien, ahora ya tienes una cantidad de novedades para mejorar los scripts que hicimos. Te acuerdas del programa listartista en el cual pasabas el nombre de un artista como parámetro y él devolvia sus músicas? Era así:
 
$ cat listartista #!/bin/bash
Changed:
<
<
# Dado um artista, mostra as suas musicas # versao 2
>
>
# Dado un artista, muestra sus músicas # versión 2
  if [ $# -eq 0 ] then
Changed:
<
<
echo Voce deveria ter passado pelo menos um parametro
>
>
echo Usted debería haber pasado al menos un parámetro
  exit 1 fi
Line: 468 to 468
 done
Changed:
<
<
     - Claro que me lembro!...
>
>
     - Claro que me acuerdo!...

     - Entonces para afirmar los conceptos que te pasé, hazlo con la pantalla formatada, en loop, de forma que solamente termine cuando reciba un <ENTER> puro en el nombre del artista. Ahhh! Cuando la lista llegue a la antepenúltima línea de la pantalla, el programa deberá dar una parada para que el operador pueda leerlas, o sea, suponga que la pantalla tenga 25 linhas. A cada 22 músicas listadas (cantidad de líneas menos 3) el programa aguardará a que el operador teclee algo para entonces continuar. Eventuales mensajes de error deben ser pasados usando la rutina mandamsg.func que acabamos de hacer.

     - Mozo, trae dos más, el mio con poca presión...

 
Changed:
<
<
     - Então para firmar os conceitos que te passei, faça ele com a tela formatada, em loop, de forma que ele só termine quando receber um <ENTER> puro no nome do artista. Ahhh! Quando a listagem atingir a antepenúltima linha da tela, o programa deverá dar uma parada para que o operador possa lê-las, isto é, suponha que a tela tenha 25 linhas. A cada 22 músicas listadas (quantidade de linhas menos 3) o programa aguardará que o operador tecle algo para então prosseguir. Eventuais mensagens de erro devem ser passadas usando a rotina mandamsg.func que acabamos de desenvolver.
>
>
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:
<
<
     - Chico, manda mais dois, o meu é com pouca pressão...
>
>
Gracias y hasta la próxima!
 
Deleted:
<
<
Não se esqueça, qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para julio.neves@gmail.com. Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em Shell que mande um e-mail para julio.neves@uniriotec.br para informar-se.
 
Changed:
<
<
Valeu!
>
>
-- HumbertoPina - 10 Jan 2007
 

-- PatricioReich - 24 Nov 2006

Revision 408 Jan 2007 - Main.HumbertoPina

Line: 1 to 1
 

Conversa de bar Parte VIII



Changed:
<
<
     - Hola amigo, como estas?
>
>
     - Hola amigo, como estás?
 
Changed:
<
<
     - Que bueno!, queria mostrarte lo que hice pero ya sé que tu quieres ir rapido a lo que interesa, no?
>
>
     - Muy bien!, queria mostrarte lo que hice pero ya sé que tu quieres ir rapido a lo que interesa, no?
 
Changed:
<
<
     - Solo para hacerte la contra, hoy voy a dejar que me muestres tu "chatarra". Dale, muestrame lo que hiciste.
>
>
     - Solo para hacerte la contra, hoy voy a dejar que me muestres tu "programita". Dale, muestrame lo que hiciste.
 
Changed:
<
<
     - Ahhh ... el ejercício que me pasaste es muy complicado. Yo lo resolvi asi:
>
>
     - Ahhh ... el ejercício que me pasaste es muy extenso. Yo lo resolvi así:
 
$ cat musinc5
Line: 17 to 17
 # Cadastra CDs (versión 5) # clear
Changed:
<
<
LineaMesg=$((`tput lines` - 3)) # Linea que mensajes seran dados para el operador
>
>
LineaMesg=$((`tput lines` - 3)) # Linea que mensajes seran pasados para el operador
 TotCols=$(tput cols) # Cantidad de columnas de la pantalla para encuadrar mensajes echo "   Inclusión de Músicas
Line: 35 to 35
 do tput cup 5 38; tput el # Posiciona y limpia linea read Albun
Changed:
<
<
[ ! "$Albun" ] && # Operador dio <ENTER>
>
>
[ ! "$Albun" ] && # Operador dió <ENTER>
  { Msg="Desea Terminar? (S/n)"         TamMsg=${#Msg}
Line: 66 to 66
  ((Track++)) tput cup 7 38 echo $Track
Changed:
<
<
tput cup 9 38 # Posiciona para leer musica
>
>
tput cup 9 38 # Posiciona para leer música
  read Musica
Changed:
<
<
[ "$Musica" ] || # Si el operador dio ...
>
>
[ "$Musica" ] || # Si el operador dió ...
  { Msg="Fin del Álbun? (S/n)"             TamMsg=${#Msg}
Line: 94 to 94
 done
Changed:
<
<
     - Si el programa esta bueno, esta todo bien estructurado, pero me gustaria que me comentes un poco que fue lo que hiciste:
>
>
     - Si, el programa esta bien, esta todo bien estructurado, pero me gustaria comentarte un poco lo que hiciste:
 
Changed:
<
<
  • Solo para recordarte, las siguientes construcciones: [ ! $Albun ] && y [ $Musica ] || representan lo mismo, en el primer caso, testamos si la variáble $Album no (!) tiene nada adentro, entonces (&&) ... y en el segundo, testamos si $Musica dio, si no (||) ...
  • Si reclamaste por el tamaño, es porque todavia no te pase algunos trucos. Fijate que la mayor parte del script es para dar mensajes centrados en la penúltima linea de la pantalla. Fijate también que algunos mensajes piden un S o un N y otros son solo de advertencia. Seria el caso típico del uso de funciones, que serian escritas solamente una vez y llamadas para ejecutar en diversos puntos del script . Voy a hacer dos funciones para resolver estos casos y vamos a incorporarlas a tu programa para ver el resultado final.
>
>
  • Solo para recordarte, las siguientes construcciones: [ ! $Albun ] && y [ $Musica ] || representan lo mismo, en el primer caso, testamos si la variáble $Album no (!) tiene nada adentro, entonces (&&) ... y en el segundo, testamos lo mismo en $Musica, si no (||) ...
  • Si reclamaste por el tamaño, es porque todavia no te pase algunos trucos. Fijate que la mayor parte del script es para dar mensajes centrados en la penúltima linea de la pantalla. Fijate también que algunos mensajes piden un S o un N y otros son sólo de advertencia. Sería el caso típico del uso de funciones, que serían escritas solamente una vez y llamadas para ejecutar en diversos puntos del script . Voy a hacer dos funciones para resolver estos casos y vamos a incorporarlas a tu programa para ver el resultado final.
 

Funciones

Changed:
<
<
     - Pepé! Ahora traeme dos chops bien helados, uno sin espuma, para que me de inspiración.
>
>
     - Mozo! Ahora traeme dos chops bien helados, uno sin espuma, para que me de inspiración.
 
    Pregunta ()
        {
Changed:
<
<
# La función recibe 3 parametros en la siguiente orden:
>
>
# La función recibe 3 parametros en el siguiente orden:
  # $1 - Mensaje que será mostrado en la pantalla # $2 - Valor que será aceptado como respuesta default # $3 - Otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, la linea a
Changed:
<
<
# seguir colocaria en Msg el valor "Acepta? (S/n)"
>
>
# seguir colocaría en Msg el valor "Acepta? (S/n)"
  local Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" local TamMsg?=${#Msg} local Col=$(((TotCols? - TamMsg?) / 2)) # Centra mensaje en la linea
Line: 126 to 126
  }
Changed:
<
<
Como podemos ver, una función es definida cuando hacemos nombre_de_la_función () y todo su cuerpo esta entre llaves ({}). Así como conversamos aqui en el Bar sobre pasar parametros, las funciones los reciben de la misma forma, o sea, son parametros posicionales ($1, $2, ..., $n) y todas las reglas que se aplican al pase de parametros para programas, también valen para funciones, pero es muy importante aclarar que los parametros pasados para un programa no se confunden con aquellos que este paso para sus funciones. Esto significa, por ejemplo, que el $1 de un script es diferente del $1 de una de sus funciones.
>
>
Como podemos ver, una función es definida cuando hacemos nombre_de_la_función () y todo su cuerpo esta entre llaves ({}). Así como conversamos aqui en el Bar sobre pasar parámetros, las funciones los reciben de la misma forma, o sea, son parámetros de posición ($1, $2, ..., $n) y todas las reglas que se aplican al pase de parámetros para programas, también valen para funciones, pero es muy importante aclarar que los párametros pasados para un programa no se mezclan con aquellos que éste pasó para sus funciones. Esto significa, por ejemplo, que el $1 de un script es diferente del $1 de una de sus funciones.
 
Changed:
<
<
Fijate que las variables $Msg, $TamMsg y $Col son de uso restricto de esta rutina, y por eso fueron creadas como local. La finalidad de esto es simplemente para economizar memória, ya que al salir de la rutina, ellas serán destruidas de la partición y si por acaso no tuviese usado este artifício, estarian residentes en la memória.
>
>
Fíjate que las variables $Msg, $TamMsg y $Col son de uso restricto de esta rutina, y por eso fueron creadas como local. La finalidad de esto es simplemente economizar memória, ya que al salir de la rutina, ellas serán destruidas de la partición y si por acaso no tuviese usado este artifício, estarian residentes en la memória.
 
Changed:
<
<
La linea de código que crea local Msg, junta el texto recibido ($1) abre parentesis, la respuesta default ($2) en mayuscula, una barra, la otra respuesta ($3) en minuscula y finaliza cerrando el parentesis. Uso esta forma para, que al mismo tiempo, pueda mostrar las opciones disponibles y destacar la respuesta ofrecida como default.
>
>
La linea de código que crea local Msg, junta el texto recibido ($1) abre parentesis, la respuesta default ($2) en mayuscula, una barra, la otra respuesta ($3) en minúscula y finaliza cerrando el paréntesis. Uso esta forma para, que al mismo tiempo, pueda mostrar las opciones disponibles y destacar la respuesta ofrecida como default.
  Casi al fin de la rutina, la respuesta recibida ($SN) es pasada para minuscula de forma que en el cuerpo del programa no se necesite hacer esta prueba.
Line: 139 to 139
 
    function MandaMsg
        {
Changed:
<
<
# La función recibe solamente un parametro
>
>
# La función recibe solamente un parámetro
  # con el mensaje que se desea mostrar, # para no obligar al programador que pase # el mensaje entre comillas, usaremos $* (todos
Line: 155 to 155
  }
Changed:
<
<
Esta es otra forma de definir una función: no la llamamos como en el ejemplo anterior usando una construcción con la sintaxis nombre_de_la_función (), pero si como function nombre_de_la_función. No tiene ninguna diferencia con la anterior, excepto que, como consta en los comentários, usamos la variable $* que como ya sabemos es el conjunto de todos los parametros pasados, para que el programador no necesite usar comillas envolviendo el mensaje que desea pasar para la función.
>
>
Esta es otra forma de definir una función: no la llamamos como en el ejemplo anterior usando una construcción con la sintaxis nombre_de_la_función (), sino como function nombre_de_la_función. No tiene ninguna diferencia con la anterior, excepto que, como consta en los comentários, usamos la variable $* que como ya sabemos es el conjunto de todos los parametros pasados, para que el programador no necesite usar comillas envolviendo el mensaje que desea pasar para la función.
  Para terminar con este blá-blá-blá vamos a ver entonces las alteraciones que el programa necesita cuando usamos el concepto de funciones:
Line: 166 to 166
 #

# Área de las variables globales

Changed:
<
<
LineaMesg=$((`tput lines` - 3)) # Linea que mensajes seran dados para el operador
>
>
LineaMesg=$((`tput lines` - 3)) # Linea que mensajes serán dados para el operador
 TotCols=$(tput cols) # Cantidad de columnas de la pantalla para encuadrar mensajes

# Área de las funciones Pregunta () {

Changed:
<
<
# La función recibe 3 parametros en la siguiente orden:
>
>
# La función recibe 3 parámetros en el siguiente orden:
  # $1 - Mensaje que será mostrado en la pantalla # $2 - Valor que será aceptado como respuesta default # $3 - Otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, la linea a
Changed:
<
<
# seguir colocaria en Msg el valor "Acepta? (S/n)"
>
>
# seguir colocaría en Msg el valor "Acepta? (S/n)"
  local Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" local TamMsg=${#Msg} local Col=$(((TotCols - TamMsg) / 2)) # Centra mensaje en la linea
Line: 225 to 225
 do tput cup 5 38; tput el # Posiciona y limpia linea read Albun
Changed:
<
<
[ ! "$Albun" ] && # Operador dio
>
>
[ ! "$Albun" ] && # Operador dió
  { Pregunta "Desea Terminar" s n
Changed:
<
<
[ $SN = "n" ] && continue # Ahora solo prueba la minuscula
>
>
[ $SN = "n" ] && continue # Ahora sólo prueba la minúscula
  clear; exit # Fin de la ejecución } grep -iq "^$Albun\^" musicas 2> /dev/null && {
Changed:
<
<
    MandaMsg Este álbun ya esta cadastrado
>
>
    MandaMsg Este álbun ya esta catastrado
  continue # Vuelve para leer otro álbun } Reg="$Albun^" # $Reg recibirá los datos de grabación
Line: 243 to 243
  ((Track++)) tput cup 7 38 echo $Track
Changed:
<
<
tput cup 9 38 # Posiciona para leer musica
>
>
tput cup 9 38 # Posiciona para leer música
  read Musica [ "$Musica" ] || # Si el operador dio ... {
Line: 273 to 273
 
  Cuerpo del Programa  
Changed:
<
<
Esta estruturação é devido ao Shell ser uma linguagem interpretada e desta forma o programa é lido da esquerda para a direita e de cima para baixo e uma variável para ser vista simultaneamente pelo script e suas funções deve ser declarada (ou inicializada) antes de qualquer coisa. As funções por sua vez devem ser declaradas antes do corpo do programa propriamente dito porque no ponto em que o programador mencionou seu nome, o interpretador Shell já o havia antes localizado e registrado que era uma função.
>
>
Esta estruturação es debido a que el Shell es un lenguaje interpretado y así el programa es leído de izquierda a derecha y de arriba para abajo y una variable para ser vista simultáneamente por el script y sus funciones debe ser declarada (o inicializada) antes de cualquier cosa. Las funciones deben ser declaradas antes del cuerpo del programa propriamente dicho porque en el lugar en que el programador mencionó su nombre, el interpretador Shell ya lo habia localizado antes y registrado que era una función.
 
Changed:
<
<
Uma coisa bacana no uso de funções é fazê-las o mais genérico possível de forma que elas sirvam para outras aplicações, sem necessidade de serem reescritas. Essas duas que acabamos de ver têm uso generalizado, pois é difícil um script que tenha uma entrada de dados pelo teclado que não use uma rotina do tipo da MandaMsg ou não interage com o operador por algo semelhante à Pergunta.
>
>
Una cosa muy buena enel uso de funciones es hacerlas lo más generales posibles de forma que sirvan para otras aplicaciones, sin necesidad de tener que reescribirlas. Esas dos que acabamos de ver tiene uso general, pues es dificil hallar un script que tenga una entrada de datos por teclado que no use una rutina del tipo de la MandaMsg o no interacciona con el operador a través de algo parecido a Pergunta.
 
Changed:
<
<
Conselho de amigo: crie um arquivo e cada função nova que você criar, anexe-a a este arquivo. Ao final de um tempo você terá uma bela biblioteca de funções que lhe poupará muito tempo de programação.
>
>
Consejo de amigo: crie un archivo y cada función nueva que críes, anéxela a este archivo. Al final de un tiempo tendrás una bella biblioteca de funciones que te ahorrará mucho tiempo de programación.
 

O comando source

Revision 324 Nov 2006 - PatricioReich

Line: 1 to 1
 

Conversa de bar Parte VIII


Line: 17 to 17
 # Cadastra CDs (versión 5) # clear
Changed:
<
<
LineaMesg=$((`tput lines` - 3)) # Linea que mensajes seran dadas para operador TotCols=$(tput cols) # Cantidad columnas de la pantalla para encuadrar mensajes
>
>
LineaMesg=$((`tput lines` - 3)) # Linea que mensajes seran dados para el operador TotCols=$(tput cols) # Cantidad de columnas de la pantalla para encuadrar mensajes
 echo "   Inclusión de Músicas     ========= == =======
Line: 126 to 126
  }
Changed:
<
<
Como podemos ver, uma função é definida quando fazemos nome_da_função () e todo o seu corpo está entre chaves ({}). Assim como conversamos aqui no Boteco sobre passagem de parâmetros, as funções os recebem da mesma forma, isto é, são parâmetros posicionais ($1, $2, ..., $n) e todas as regras que se aplicam a passagem de parâmetros para programas, também valem para funções, mas é muito importante realçar que os parâmetros passados para um programa não se confundem com aqueles que este passou para suas funções. Isso significa, por exemplo, que o $1 de um script é diferente do $1 de uma de suas funções
>
>
Como podemos ver, una función es definida cuando hacemos nombre_de_la_función () y todo su cuerpo esta entre llaves ({}). Así como conversamos aqui en el Bar sobre pasar parametros, las funciones los reciben de la misma forma, o sea, son parametros posicionales ($1, $2, ..., $n) y todas las reglas que se aplican al pase de parametros para programas, también valen para funciones, pero es muy importante aclarar que los parametros pasados para un programa no se confunden con aquellos que este paso para sus funciones. Esto significa, por ejemplo, que el $1 de un script es diferente del $1 de una de sus funciones.
 
Changed:
<
<
Repare que as variáveis $Msg, $TamMsg e $Col são de uso restrito desta rotina, e por isso foram criadas como local. A finalidade disso é simplesmente para economizar memória, já que ao sair da rotina, elas serão devidamente detonadas da partição e caso não tivesse usado este artifício, permaneceriam residentes.
>
>
Fijate que las variables $Msg, $TamMsg y $Col son de uso restricto de esta rutina, y por eso fueron creadas como local. La finalidad de esto es simplemente para economizar memória, ya que al salir de la rutina, ellas serán destruidas de la partición y si por acaso no tuviese usado este artifício, estarian residentes en la memória.
 
Changed:
<
<
A linha de código que cria local Msg, concatena ao texto recebido ($1) um abre parênteses, a resposta default ($2) em caixa alta, uma barra, a outra resposta ($3) em caixa baixa e finaliza fechando o parênteses. Uso esta convenção para, ao mesmo tempo, mostrar as opções disponíveis e realçar a resposta oferecida como default.
>
>
La linea de código que crea local Msg, junta el texto recibido ($1) abre parentesis, la respuesta default ($2) en mayuscula, una barra, la otra respuesta ($3) en minuscula y finaliza cerrando el parentesis. Uso esta forma para, que al mismo tiempo, pueda mostrar las opciones disponibles y destacar la respuesta ofrecida como default.
 
Changed:
<
<
Quase ao fim da rotina, a resposta recebida ($SN) é passada para caixa baixa de forma que no corpo do programa não se precise fazer este teste.
>
>
Casi al fin de la rutina, la respuesta recibida ($SN) es pasada para minuscula de forma que en el cuerpo del programa no se necesite hacer esta prueba.
 
Changed:
<
<
Veja agora como ficaria a função para dar uma mensagem na tela:
>
>
Veamos ahora como quedaria la función para dar un mensaje en la pantalla:
 
    function MandaMsg
        {
Changed:
<
<
# A função recebe somente um parâmetro # com a mensagem que se deseja exibir, # para não obrigar ao programador passar # a msq entre aspas, usaremos $* (todos # os parâmetro, lembra?) e não $1.
>
>
# La función recibe solamente un parametro # con el mensaje que se desea mostrar, # para no obligar al programador que pase # el mensaje entre comillas, usaremos $* (todos # los parametros, te acuerdas?) y no $1.
  local Msg="$*" local TamMsg?=${#Msg}
Changed:
<
<
local Col=$(((TotCols? - TamMsg?) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col
>
>
local Col=$(((TotCols? - TamMsg?) / 2)) # Centra el mensaje en la linea tput cup $LineaMesg $Col
  echo "$Msg" read -n1
Changed:
<
<
tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da função
>
>
tput cup $LineaMesg $Col; tput el # Borra el mensaje de la pantalla return # Sale de la función
  }
Changed:
<
<
Esta é uma outra forma de definir uma função: não a chamamos como no exemplo anterior usando uma construção com a sintaxe nome_da_função (), mas sim como function nome_da_função. Quanto ao mais, nada difere da anterior, exceto que, como consta dos comentários, usamos a variável $* que como já sabemos é o conjunto de todos os parâmetros passados, para que o programador não precise usar aspas envolvendo a mensagem que deseja passar para a função.
>
>
Esta es otra forma de definir una función: no la llamamos como en el ejemplo anterior usando una construcción con la sintaxis nombre_de_la_función (), pero si como function nombre_de_la_función. No tiene ninguna diferencia con la anterior, excepto que, como consta en los comentários, usamos la variable $* que como ya sabemos es el conjunto de todos los parametros pasados, para que el programador no necesite usar comillas envolviendo el mensaje que desea pasar para la función.
 
Changed:
<
<
Para terminar com este blá-blá-blá vamos ver então as alterações que o programa necessita quando usamos o conceito de funções:
>
>
Para terminar con este blá-blá-blá vamos a ver entonces las alteraciones que el programa necesita cuando usamos el concepto de funciones:
 
$ cat musinc6 #!/bin/bash
Changed:
<
<
# Cadastra CDs (versao 6)
>
>
# Cadastra CDs (versión 6)
 #
Changed:
<
<
# Área de variáveis globais LinhaMesg=$((`tput lines` - 3)) # Linha que msgs serão dadas para operador TotCols=$(tput cols) # Qtd colunas da tela para enquadrar msgs
>
>
# Área de las variables globales LineaMesg=$((`tput lines` - 3)) # Linea que mensajes seran dados para el operador TotCols=$(tput cols) # Cantidad de columnas de la pantalla para encuadrar mensajes
 
Changed:
<
<
# Área de funções Pergunta ()
>
>
# Área de las funciones Pregunta ()
  {
Changed:
<
<
# A função recebe 3 parâmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default # $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha # abaixo colocaria em Msg o valor "Aceita? (S/n)"
>
>
# La función recibe 3 parametros en la siguiente orden: # $1 - Mensaje que será mostrado en la pantalla # $2 - Valor que será aceptado como respuesta default # $3 - Otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, la linea a # seguir colocaria en Msg el valor "Acepta? (S/n)"
  local Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" local TamMsg=${#Msg}
Changed:
<
<
local Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col
>
>
local Col=$(((TotCols - TamMsg) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col
  echo "$Msg"
Changed:
<
<
tput cup $LinhaMesg $((Col + TamMsg + 1))
>
>
tput cup $LineaMesg $((Col + TamMsg + 1))
  read -n1 SN
Changed:
<
<
[ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A saída de SN será em minúscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da função
>
>
[ ! $SN ] && SN=$2 # Si vacia coloca default en SN echo $SN | tr A-Z a-z # La salida de SN será en minúscula tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla return # Sale de la función
  } function MandaMsg {
Changed:
<
<
# A função recebe somente um parâmetro # com a mensagem que se deseja exibir, # para não obrigar ao programador passar # a msq entre aspas, usaremos $* (todos # os parâmetro, lembra?) e não $1.
>
>
# La función recibe solamente un parametro # con el mensaje que se desea mostrar, # para no obligar al programador que pase # el mensaje entre comillas, usaremos $* (todos # los parametros, te acuerdas?) y no $1.
  local Msg="$*" local TamMsg=${#Msg}
Changed:
<
<
local Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col
>
>
local Col=$(((TotCols - TamMsg) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col
  echo "$Msg" read -n1
Changed:
<
<
tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da função
>
>
tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla return # Sale de la función
  }
Changed:
<
<
# O corpo do programa propriamente dito começa aqui
>
>
# El cuerpo del programa propiamente dicho comienza aqui
 clear echo "
Changed:
<
<
Inclusao de Músicas     ======== == =======
>
>
  Inclusión de Músicas     ========= == =======
    
Changed:
<
<
  Título do Álbum:   | Este campo foi   Faixa: < criado somente para   | orientar o preenchimento   Nome da Música:
>
>
  Título del Álbun:   | Este campo fue   Track: < creado solamente para   | orientar como llenar   Nombre de la Música:
  
Changed:
<
<
  Intérprete:" # Tela montada com um único echo
>
>
  Intérprete:" # Pantalla montada con un único echo
 while true do
Changed:
<
<
tput cup 5 38; tput el # Posiciona e limpa linha read Album [ ! "$Album" ] && # Operador deu
>
>
tput cup 5 38; tput el # Posiciona y limpia linea read Albun [ ! "$Albun" ] && # Operador dio
  {
Changed:
<
<
Pergunta "Deseja Terminar" s n [ $SN = "n" ] && continue # Agora só testo a caixa baixa clear; exit # Fim da execução
>
>
Pregunta "Desea Terminar" s n [ $SN = "n" ] && continue # Ahora solo prueba la minuscula clear; exit # Fin de la ejecución
  }
Changed:
<
<
grep -iq "^$Album\^" musicas 2> /dev/null &&
>
>
grep -iq "^$Albun\^" musicas 2> /dev/null &&
  {
Changed:
<
<
    MandaMsg Este álbum já está cadastrado continue # Volta para ler outro álbum
>
>
    MandaMsg Este álbun ya esta cadastrado continue # Vuelve para leer otro álbun
  }
Changed:
<
<
Reg="$Album^" # $Reg receberá os dados de gravação oArtista= # Guardará artista anterior
>
>
Reg="$Albun^" # $Reg recibirá los datos de grabación elArtista= # Grabará artista anterior
  while true do
Changed:
<
<
((Faixa++))
>
>
((Track++))
  tput cup 7 38
Changed:
<
<
echo $Faixa tput cup 9 38 # Posiciona para ler musica
>
>
echo $Track tput cup 9 38 # Posiciona para leer musica
  read Musica
Changed:
<
<
[ "$Musica" ] || # Se o operador tiver dado ...
>
>
[ "$Musica" ] || # Si el operador dio ...
  {
Changed:
<
<
Pergunta "Fim de Álbum?" s n [ "$SN" = n ] && continue # Agora só testo a caixa baixa break # Sai do loop para gravar dados
>
>
Pregunta "Fin de Álbun?" s n [ "$SN" = n ] && continue # Ahora solo prueba la minuscula break # Sale del loop para grabar datos
  }
Changed:
<
<
tput cup 11 38 # Posiciona para ler Artista [ "$oArtista" ]&& echo -n "($oArtista) " # Artista anterior é default
>
>
tput cup 11 38 # Posiciona para leer Artista [ "$elArtista" ]&& echo -n "($elArtista) " # Artista anterior es default
  read Artista
Changed:
<
<
[ "$Artista" ] && oArtista="$Artista" Reg="$Reg$oArtista~$Musica:" # Montando registro tput cup 9 38; tput el # Apaga Musica da tela tput cup 11 38; tput el # Apaga Artista da tela
>
>
[ "$Artista" ] && elArtista="$Artista" Reg="$Reg$elArtista~$Musica:" # Montando registro tput cup 9 38; tput el # Borra Musica de la pantalla tput cup 11 38; tput el # Borra Artista de la pantalla
  done
Changed:
<
<
echo "$Reg" >> musicas # Grava registro no fim do arquivo sort musicas -o musicas # Classifica o arquivo
>
>
echo "$Reg" >> musicas # Graba registro en el fin del archivo sort musicas -o musicas # Clasifica el archivo
 done
Changed:
<
<
Repare que a estruturação do _script_está conforme o gráfico a seguir:
>
>
Fijate que la estructura del _script_esta como en el gráfico de abajo:
 
Changed:
<
<
  Corpo do Programa  
Variáveis Globais
Funções
>
>
  Cuerpo del Programa  
Variables Globales
Funciones
 

Esta estruturação é devido ao Shell ser uma linguagem interpretada e desta forma o programa é lido da esquerda para a direita e de cima para baixo e uma variável para ser vista simultaneamente pelo script e suas funções deve ser declarada (ou inicializada) antes de qualquer coisa. As funções por sua vez devem ser declaradas antes do corpo do programa propriamente dito porque no ponto em que o programador mencionou seu nome, o interpretador Shell já o havia antes localizado e registrado que era uma função.

Line: 479 to 479
 Valeu!
Changed:
<
<
-- PatricioReich - 22 Nov 2006
>
>
-- PatricioReich - 24 Nov 2006

Revision 223 Nov 2006 - PatricioReich

Line: 1 to 1
 

Conversa de bar Parte VIII


Line: 7 to 7
       - Que bueno!, queria mostrarte lo que hice pero ya sé que tu quieres ir rapido a lo que interesa, no?
Changed:
<
<
     - Solo para hacerte la contra, hoy voy a dejar que me muestres tu "chatarra". Me vas a mostrar lo que hiciste?
>
>
     - Solo para hacerte la contra, hoy voy a dejar que me muestres tu "chatarra". Dale, muestrame lo que hiciste.
       - Ahhh ... el ejercício que me pasaste es muy complicado. Yo lo resolvi asi:
Line: 17 to 17
 # Cadastra CDs (versión 5) # clear
Changed:
<
<
LineaMesg=$((`tput lines` - 3)) # Linea que msgs seran dadas para operador TotCols=$(tput cols) # Cantidad columnas de la pantalla para encuadrar msgs
>
>
LineaMesg=$((`tput lines` - 3)) # Linea que mensajes seran dadas para operador TotCols=$(tput cols) # Cantidad columnas de la pantalla para encuadrar mensajes
 echo "   Inclusión de Músicas     ========= == =======
Line: 39 to 39
  { Msg="Desea Terminar? (S/n)"         TamMsg=${#Msg}
Changed:
<
<
Col=$(((TotCols - TamMsg) / 2)) # Centra msg en la linea
>
>
Col=$(((TotCols - TamMsg) / 2)) # Centra mensaje en la linea
  tput cup $LineaMesg $Col echo "$Msg" tput cup $LineaMesg $((Col + TamMsg + 1)) read -n1 SN
Changed:
<
<
tput cup $LineaMesg $Col; tput el # Borra msg de la pantalla
>
>
tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla
  [ $SN = "N" -o $SN = "n" ] && continue # $SN es igual a N o (-o) n? clear; exit # Fin de la ejecución }
Line: 52 to 52
  { Msg="Este álbun ya está cadastrado"         TamMsg=${#Msg}
Changed:
<
<
Col=$(((TotCols - TamMsg) / 2)) # Centra msg en la linea
>
>
Col=$(((TotCols - TamMsg) / 2)) # Centra mensaje en la linea
  tput cup $LineaMesg $Col echo "$Msg" read -n1
Changed:
<
<
tput cup $LineaMesg $Col; tput el # Borra msg de la pantalla
>
>
tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla
  continue # Vuelve para leer otro álbun } Reg="$Albun^" # $Reg recibirá los datos para grabación
Line: 72 to 72
  { Msg="Fin del Álbun? (S/n)"             TamMsg=${#Msg}
Changed:
<
<
Col=$(((TotCols - TamMsg) / 2)) # Centra msg en la linea
>
>
Col=$(((TotCols - TamMsg) / 2)) # Centra mensaje en la linea
  tput cup $LineaMesg $Col echo "$Msg" tput cup $LineaMesg $((Col + TamMsg + 1) read -n1 SN
Changed:
<
<
tput cup $LineaMesg $Col; tput el # Borra msg de la pantalla
>
>
tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla
  [ "$SN" = N -o "$SN" = n ]&&continue # $SN es igual a N o (-o) n? break # Sale del loop para grabar }
Line: 94 to 94
 done
Changed:
<
<
     - É o programa tá legal, tá todo estruturadinho, mas gostaria de alguns poucos comentários sobre o que você fez:
>
>
     - Si el programa esta bueno, esta todo bien estructurado, pero me gustaria que me comentes un poco que fue lo que hiciste:
 
Changed:
<
<
  • Só para relembrar, as seguintes construções: [ ! $Album ] && e [ $Musica ] || representam a mesma coisa, isto é, no caso da primeira, o testamos se a variável $Album não (!) tem nada dentro, então (&&) ... Na segunda, testamos se $Musica tem dado, senão (||) ...
  • Se você reclamou do tamanho dele, é porque ainda não dei algumas dicas. Repare que a maior parte do script é para dar mensagens centradas na penúltima linha da tela. Repare ainda que algumas mensagens pedem um S ou um N e outras são só de advertência. Seria o caso típico do uso de funções, que seriam escritas somente uma vez e chamada a execução de diversos pontos do script. Vou montar duas funções para resolver estes casos e vamos incorporá-las ao seu programa para ver o resultado final.
>
>
  • Solo para recordarte, las siguientes construcciones: [ ! $Albun ] && y [ $Musica ] || representan lo mismo, en el primer caso, testamos si la variáble $Album no (!) tiene nada adentro, entonces (&&) ... y en el segundo, testamos si $Musica dio, si no (||) ...
  • Si reclamaste por el tamaño, es porque todavia no te pase algunos trucos. Fijate que la mayor parte del script es para dar mensajes centrados en la penúltima linea de la pantalla. Fijate también que algunos mensajes piden un S o un N y otros son solo de advertencia. Seria el caso típico del uso de funciones, que serian escritas solamente una vez y llamadas para ejecutar en diversos puntos del script . Voy a hacer dos funciones para resolver estos casos y vamos a incorporarlas a tu programa para ver el resultado final.
 
Changed:
<
<

Funções

>
>

Funciones

 
Changed:
<
<
     - Chico! Agora traz dois chopes, sendo um sem colarinho, para me dar inspiração.
>
>
     - Pepé! Ahora traeme dos chops bien helados, uno sin espuma, para que me de inspiración.
 
Changed:
<
<
Pergunta ()
>
>
Pregunta ()
  {
Changed:
<
<
# A função recebe 3 parâmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default # $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha a # seguir colocaria em Msg o valor "Aceita? (S/n)"
>
>
# La función recibe 3 parametros en la siguiente orden: # $1 - Mensaje que será mostrado en la pantalla # $2 - Valor que será aceptado como respuesta default # $3 - Otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, la linea a # seguir colocaria en Msg el valor "Acepta? (S/n)"
  local Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" local TamMsg?=${#Msg}
Changed:
<
<
local Col=$(((TotCols? - TamMsg?) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col
>
>
local Col=$(((TotCols? - TamMsg?) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col
  echo "$Msg"
Changed:
<
<
tput cup $LinhaMesg $((Col + TamMsg? + 1))
>
>
tput cup $LineaMesg $((Col + TamMsg? + 1))
  read -n1 SN
Changed:
<
<
[ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A saída de SN será em minúscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da função
>
>
[ ! $SN ] && SN=$2 # Si vacia coloca default en SN echo $SN | tr A-Z a-z # La salida de SN será en minúscula tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla return # Sale de la función
  }

Revision 122 Nov 2006 - PatricioReich

Line: 1 to 1
Added:
>
>

Conversa de bar Parte VIII



     - Hola amigo, como estas?

     - Que bueno!, queria mostrarte lo que hice pero ya sé que tu quieres ir rapido a lo que interesa, no?

     - Solo para hacerte la contra, hoy voy a dejar que me muestres tu "chatarra". Me vas a mostrar lo que hiciste?

     - Ahhh ... el ejercício que me pasaste es muy complicado. Yo lo resolvi asi:

$ cat musinc5 #!/bin/bash # Cadastra CDs (versión 5) # clear LineaMesg=$((`tput lines` - 3)) # Linea que msgs seran dadas para operador TotCols=$(tput cols) # Cantidad columnas de la pantalla para encuadrar msgs echo "   Inclusión de Músicas     ========= == =======       Título del Álbun:   | Este campo fue   Track: < creado solamente para   | orientar como llenar   Nombre de la Música:     Intérprete:" # Pantalla montada con un único echo while true do tput cup 5 38; tput el # Posiciona y limpia linea read Albun [ ! "$Albun" ] && # Operador dio <ENTER> { Msg="Desea Terminar? (S/n)"         TamMsg=${#Msg} Col=$(((TotCols - TamMsg) / 2)) # Centra msg en la linea tput cup $LineaMesg $Col echo "$Msg" tput cup $LineaMesg $((Col + TamMsg + 1)) read -n1 SN tput cup $LineaMesg $Col; tput el # Borra msg de la pantalla [ $SN = "N" -o $SN = "n" ] && continue # $SN es igual a N o (-o) n? clear; exit # Fin de la ejecución } grep "^$Albun\^" musicas > /dev/null && { Msg="Este álbun ya está cadastrado"         TamMsg=${#Msg} Col=$(((TotCols - TamMsg) / 2)) # Centra msg en la linea tput cup $LineaMesg $Col echo "$Msg" read -n1 tput cup $LineaMesg $Col; tput el # Borra msg de la pantalla continue # Vuelve para leer otro álbun } Reg="$Albun^" # $Reg recibirá los datos para grabación elArtista= # Variable que graba artista anterior while true do ((Track++)) tput cup 7 38 echo $Track tput cup 9 38 # Posiciona para leer musica read Musica [ "$Musica" ] || # Si el operador dio ... { Msg="Fin del Álbun? (S/n)"             TamMsg=${#Msg} Col=$(((TotCols - TamMsg) / 2)) # Centra msg en la linea tput cup $LineaMesg $Col echo "$Msg" tput cup $LineaMesg $((Col + TamMsg + 1) read -n1 SN tput cup $LineaMesg $Col; tput el # Borra msg de la pantalla [ "$SN" = N -o "$SN" = n ]&&continue # $SN es igual a N o (-o) n? break # Sale del loop para grabar } tput cup 11 38 # Posiciona para leer Artista [ "$elArtista" ]&& echo -n "($elArtista) " # Artista anterior es default read Artista [ "$Artista" ] && elArtista="$Artista" Reg="$Reg$elArtista~$Musica:" # Montando registro tput cup 9 38; tput el # Borra Musica de la pantalla tput cup 11 38; tput el # Borra Artista de la pantalla done echo "$Reg" >> musicas # Graba registro en el fin del archivo sort musicas -0 musicas # Clasifica el archivo done

     - É o programa tá legal, tá todo estruturadinho, mas gostaria de alguns poucos comentários sobre o que você fez:

  • Só para relembrar, as seguintes construções: [ ! $Album ] && e [ $Musica ] || representam a mesma coisa, isto é, no caso da primeira, o testamos se a variável $Album não (!) tem nada dentro, então (&&) ... Na segunda, testamos se $Musica tem dado, senão (||) ...
  • Se você reclamou do tamanho dele, é porque ainda não dei algumas dicas. Repare que a maior parte do script é para dar mensagens centradas na penúltima linha da tela. Repare ainda que algumas mensagens pedem um S ou um N e outras são só de advertência. Seria o caso típico do uso de funções, que seriam escritas somente uma vez e chamada a execução de diversos pontos do script. Vou montar duas funções para resolver estes casos e vamos incorporá-las ao seu programa para ver o resultado final.

Funções

     - Chico! Agora traz dois chopes, sendo um sem colarinho, para me dar inspiração.

    Pergunta ()
        {
        #  A função recebe 3 parâmetros na seguinte ordem:
        #  $1 - Mensagem a ser dada na tela
        #  $2 - Valor a ser aceito com resposta default
        #  $3 - O outro valor aceito
        #  Supondo que $1=Aceita?, $2=s e $3=n, a linha a
        #  seguir colocaria em Msg o valor "Aceita? (S/n)"
        local Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)"
        local TamMsg=${#Msg}
        local Col=$(((TotCols - TamMsg) / 2))  # Centra msg na linha
        tput cup $LinhaMesg $Col
        echo "$Msg"
        tput cup $LinhaMesg $((Col + TamMsg + 1))
        read -n1 SN
        [ ! $SN ] && SN=$2                     # Se vazia coloca default em SN
        echo $SN | tr A-Z a-z                  # A saída de SN será em minúscula
        tput cup $LinhaMesg $Col; tput el      # Apaga msg da tela
        return                                 # Sai da função
        }

Como podemos ver, uma função é definida quando fazemos nome_da_função () e todo o seu corpo está entre chaves ({}). Assim como conversamos aqui no Boteco sobre passagem de parâmetros, as funções os recebem da mesma forma, isto é, são parâmetros posicionais ($1, $2, ..., $n) e todas as regras que se aplicam a passagem de parâmetros para programas, também valem para funções, mas é muito importante realçar que os parâmetros passados para um programa não se confundem com aqueles que este passou para suas funções. Isso significa, por exemplo, que o $1 de um script é diferente do $1 de uma de suas funções

Repare que as variáveis $Msg, $TamMsg e $Col são de uso restrito desta rotina, e por isso foram criadas como local. A finalidade disso é simplesmente para economizar memória, já que ao sair da rotina, elas serão devidamente detonadas da partição e caso não tivesse usado este artifício, permaneceriam residentes.

A linha de código que cria local Msg, concatena ao texto recebido ($1) um abre parênteses, a resposta default ($2) em caixa alta, uma barra, a outra resposta ($3) em caixa baixa e finaliza fechando o parênteses. Uso esta convenção para, ao mesmo tempo, mostrar as opções disponíveis e realçar a resposta oferecida como default.

Quase ao fim da rotina, a resposta recebida ($SN) é passada para caixa baixa de forma que no corpo do programa não se precise fazer este teste.

Veja agora como ficaria a função para dar uma mensagem na tela:

    function MandaMsg
        {
        # A função recebe somente um parâmetro
        # com a mensagem que se deseja exibir,
        # para não obrigar ao programador passar
        # a msq entre aspas, usaremos $* (todos
        # os parâmetro, lembra?) e não $1.
        local Msg="$*"
        local TamMsg=${#Msg}
        local Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha
        tput cup $LinhaMesg $Col
        echo "$Msg"
        read -n1
        tput cup $LinhaMesg $Col; tput el     # Apaga msg da tela
        return                                # Sai da função
        }

Esta é uma outra forma de definir uma função: não a chamamos como no exemplo anterior usando uma construção com a sintaxe nome_da_função (), mas sim como function nome_da_função. Quanto ao mais, nada difere da anterior, exceto que, como consta dos comentários, usamos a variável $* que como já sabemos é o conjunto de todos os parâmetros passados, para que o programador não precise usar aspas envolvendo a mensagem que deseja passar para a função.

Para terminar com este blá-blá-blá vamos ver então as alterações que o programa necessita quando usamos o conceito de funções:

$ cat musinc6 #!/bin/bash # Cadastra CDs (versao 6) #

# Área de variáveis globais LinhaMesg=$((`tput lines` - 3)) # Linha que msgs serão dadas para operador TotCols=$(tput cols) # Qtd colunas da tela para enquadrar msgs

# Área de funções Pergunta () { # A função recebe 3 parâmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default # $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha # abaixo colocaria em Msg o valor "Aceita? (S/n)" local Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" local TamMsg=${#Msg} local Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + TamMsg + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A saída de SN será em minúscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da função } function MandaMsg { # A função recebe somente um parâmetro # com a mensagem que se deseja exibir, # para não obrigar ao programador passar # a msq entre aspas, usaremos $* (todos # os parâmetro, lembra?) e não $1. local Msg="$*" local TamMsg=${#Msg} local Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" read -n1 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da função }

# O corpo do programa propriamente dito começa aqui clear echo " Inclusao de Músicas     ======== == =======       Título do Álbum:   | Este campo foi   Faixa: < criado somente para   | orientar o preenchimento   Nome da Música:     Intérprete:" # Tela montada com um único echo while true do tput cup 5 38; tput el # Posiciona e limpa linha read Album [ ! "$Album" ] && # Operador deu { Pergunta "Deseja Terminar" s n [ $SN = "n" ] && continue # Agora só testo a caixa baixa clear; exit # Fim da execução } grep -iq "^$Album\^" musicas 2> /dev/null && {     MandaMsg Este álbum já está cadastrado continue # Volta para ler outro álbum } Reg="$Album^" # $Reg receberá os dados de gravação oArtista= # Guardará artista anterior while true do ((Faixa++)) tput cup 7 38 echo $Faixa tput cup 9 38 # Posiciona para ler musica read Musica [ "$Musica" ] || # Se o operador tiver dado ... { Pergunta "Fim de Álbum?" s n [ "$SN" = n ] && continue # Agora só testo a caixa baixa break # Sai do loop para gravar dados } tput cup 11 38 # Posiciona para ler Artista [ "$oArtista" ]&& echo -n "($oArtista) " # Artista anterior é default read Artista [ "$Artista" ] && oArtista="$Artista" Reg="$Reg$oArtista~$Musica:" # Montando registro tput cup 9 38; tput el # Apaga Musica da tela tput cup 11 38; tput el # Apaga Artista da tela done echo "$Reg" >> musicas # Grava registro no fim do arquivo sort musicas -o musicas # Classifica o arquivo done

Repare que a estruturação do _script_está conforme o gráfico a seguir:

  Corpo do Programa  
Variáveis Globais
Funções

Esta estruturação é devido ao Shell ser uma linguagem interpretada e desta forma o programa é lido da esquerda para a direita e de cima para baixo e uma variável para ser vista simultaneamente pelo script e suas funções deve ser declarada (ou inicializada) antes de qualquer coisa. As funções por sua vez devem ser declaradas antes do corpo do programa propriamente dito porque no ponto em que o programador mencionou seu nome, o interpretador Shell já o havia antes localizado e registrado que era uma função.

Uma coisa bacana no uso de funções é fazê-las o mais genérico possível de forma que elas sirvam para outras aplicações, sem necessidade de serem reescritas. Essas duas que acabamos de ver têm uso generalizado, pois é difícil um script que tenha uma entrada de dados pelo teclado que não use uma rotina do tipo da MandaMsg ou não interage com o operador por algo semelhante à Pergunta.

Conselho de amigo: crie um arquivo e cada função nova que você criar, anexe-a a este arquivo. Ao final de um tempo você terá uma bela biblioteca de funções que lhe poupará muito tempo de programação.

O comando source

Vê se você nota algo de diferente na saída do ls a seguir:

$ ls -la .bash_profile -rw-r--r-- 1 Julio unknown 4511 Mar 18 17:45 .bash_profile

Não olhe a resposta não, volte a prestar atenção! Bem, já que você está mesmo sem saco de pensar e prefere ler a resposta, vou te dar uma dica: acho que você sabe que o .bash_profile é um dos programas que são automaticamente "executados" quando você se loga (ARRGGHH! Odeio este termo). Agora que te dei esta dica olhe novamente para a saída do ls e me diga o que há de diferente nela.

Como eu disse o .bash_profile é "executado" em tempo de logon e repare que não tem nenhum direito de execução. Isso se dá porque o se você o executasse como qualquer outro script careta, quando terminasse sua execução todo o ambiente por ele gerado morreria junto com o Shell sob o qual ele foi executado (você se lembra que todos os scripts são executados em subshells, né?).

Pois é. É para coisas assim que existe o comando source, também conhecido por . (ponto). Este comando faz com que não seja criado um novo Shell (um subshell) para executar o programa que que lhe é passado como parâmetro.

Melhor um exemplo que 453 palavras. Veja este scriptizinho a seguir:

$ cat script_bobo cd .. ls

Ele simplesmente deveria ir para o diretório acima do diretório atual. Vamos executar uns comandos envolvendo o script_bobo e vamos analisar os resultados:

$ pwd /home/jneves $ script_bobo jneves juliana paula silvie $ pwd /home/jneves

Se eu mandei ele subir um diretório, porque não subiu? Subiu sim! O subshell que foi criado para executar o script tanto subiu que listou os diretórios dos quatro usuários abaixo do /home, só que assim que o script acabou, o subshell foi para o beleleu e com ele todo o ambiente criado. Olha agora como a coisa muda:

$ source script_bobo jneves juliana paula silvie $ pwd /home $ cd - /home/jneves $ . script_bobo jneves juliana paula silvie $ pwd /home

Ahh! Agora sim! Sendo passado como parâmetro do comando source ou . (ponto), o script foi executado no Shell corrente deixando neste, todo o ambiente criado. Agora damos um rewind para o início da explicação sobre este comando. Lá falamos do .bash_profile, e a esta altura você já deve saber que a sua incumbência é, logo após o login, deixar o ambiente de trabalho preparado para o usuário, e agora entendemos que é por isso mesmo que ele é executado usando este artifício.

E agora você deve estar se perguntando se é só para isso que este comando serve, e eu lhe digo que sim, mas isso nos traz um monte de vantagens e uma das mais usadas é tratar funções como rotinas externas. Veja uma outra forma de fazer o nosso programa para incluir CDs no arquivo musicas:

$ cat musinc7 #!/bin/bash # Cadastra CDs (versao 7) #

# Área de variáveis globais LinhaMesg=$((`tput lines` - 3)) # Linha que msgs serão dadas para operador TotCols=$(tput cols) # Qtd colunas da tela para enquadrar msgs

# O corpo do programa propriamente dito começa aqui clear echo " Inclusao de Músicas     ======== == =======       Título do Álbum:   | Este campo foi   Faixa: < criado somente para   | orientar o preenchimento   Nome da Música:     Intérprete:" # Tela montada com um único echo while true do tput cup 5 38; tput el # Posiciona e limpa linha read Album [ ! "$Album" ] && # Operador deu { source pergunta.func "Deseja Terminar" s n [ $SN = "n" ] && continue # Agora só testo a caixa baixa clear; exit # Fim da execução } grep -iq "^$Album\^" musicas 2> /dev/null && { . mandamsg.func Este álbum já está cadastrado continue # Volta para ler outro álbum } Reg="$Album^" # $Reg receberá os dados de gravação oArtista= # Guardará artista anterior while true do ((Faixa++)) tput cup 7 38 echo $Faixa tput cup 9 38 # Posiciona para ler musica read Musica [ "$Musica" ] || # Se o operador tiver dado ... { . pergunta.func "Fim de Álbum?" s n [ "$SN" = n ] && continue # Agora só testo a caixa baixa break # Sai do loop para gravar dados } tput cup 11 38 # Posiciona para ler Artista [ "$oArtista" ] && echo -n "($oArtista) " # Artista anter. é default read Artista [ "$Artista" ] && oArtista="$Artista" Reg="$Reg$oArtista~$Musica:" # Montando registro tput cup 9 38; tput el # Apaga Musica da tela tput cup 11 38; tput el # Apaga Artista da tela done echo "$Reg" >> musicas # Grava registro no fim do arquivo sort musicas -o musicas # Classifica o arquivo done

Agora o programa deu uma boa encolhida e as chamadas de função foram trocadas por arquivos externos chamados pergunta.func e mandamsg.func, que assim podem ser chamados por qualquer outro programa, desta forma reutilizando o seu código.

Por motivos meramente didáticos as execuções de pergunta.func e mandamsg.func estão sendo comandadas por source e por . (ponto) indiscriminadamente, embora prefira o source por ser mais visível desta forma dando maior legibilidade ao código e facilitando sua posterior manutenção.

Veja agora como ficaram estes dois arquivos:

$ cat pergunta.func # A função recebe 3 parâmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default # $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha # abaixo colocaria em Msg o valor "Aceita? (S/n)" Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" TamMsg=${#Msg} Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + zTamMsg + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A saída de SN será em minúscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela $ cat mandamsg.func # A função recebe somente um parâmetro # com a mensagem que se deseja exibir, # para não obrigar ao programador passar # a msq entre aspas, usaremos $* (todos # os parâmetro, lembra?) e não $1. Msg="$*" TamMsg=${#Msg} Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" read -n1 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela

Em ambos os arquivos, fiz somente duas mudanças que veremos nas observações a seguir, porém tenho mais três a fazer:

  1. As variáveis não estão sendo mais declaradas como local, porque está é uma diretiva que só pode ser usada no corpo de funções e portanto estas variáveis permanecem no ambiente do Shell, poluindo-o;
  2. O comando return não está mais presente mas poderia estar sem alterar em nada a lógica, uma vez que ele só serviria para indicar um eventual erro via um código de retorno previamente estabelecido (por exemplo return 1, return 2, ...), sendo que o return e return 0 são idênticos e significam rotina executada sem erros;
  3. O comando que estamos acostumados a usar para gerar código de retorno é o exit, mas a saída de uma rotina externa não pode ser feita desta forma, porque por estar sendo executada no mesmo Shell que o script chamador, o exit simplesmente encerraria este Shell, terminando a execução de todo o script;
  4. De onde surgiu a variável LinhaMesg? Ela veio do musinc7, porque ela havia sido declarada antes da chamada das rotinas (nunca esquecendo que o Shell que está interpretando o script e estas rotinas é o mesmo);
  5. Se você decidir usar rotinas externas, não se avexe, abunde os comentários (principalmente sobre a passagem dos parâmetros) para facilitar a manutenção e seu uso por outros programas no futuro.

     - Bem, agora você já tem mais um monte de novidade para melhorar os scripts que fizemos você se lembra do programa listartista no qual você passava o nome de um artista como parâmetro e ele devolvia as suas músicas? Ele era assim:

$ cat listartista #!/bin/bash # Dado um artista, mostra as suas musicas # versao 2

if [ $# -eq 0 ] then echo Voce deveria ter passado pelo menos um parametro exit 1 fi

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

     - Claro que me lembro!...

     - Então para firmar os conceitos que te passei, faça ele com a tela formatada, em loop, de forma que ele só termine quando receber um <ENTER> puro no nome do artista. Ahhh! Quando a listagem atingir a antepenúltima linha da tela, o programa deverá dar uma parada para que o operador possa lê-las, isto é, suponha que a tela tenha 25 linhas. A cada 22 músicas listadas (quantidade de linhas menos 3) o programa aguardará que o operador tecle algo para então prosseguir. Eventuais mensagens de erro devem ser passadas usando a rotina mandamsg.func que acabamos de desenvolver.

     - Chico, manda mais dois, o meu é com pouca pressão...

Não se esqueça, qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para julio.neves@gmail.com. Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em Shell que mande um e-mail para julio.neves@uniriotec.br para informar-se.

Valeu!

-- PatricioReich - 22 Nov 2006

 
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Wiki-SL? Send feedback