You are here:
Wiki-SL
>
TWikiBar Web
>
TWikiBarConversa10
(24 Feb 2008,
CollonsTorre
)
(raw view)
E
dit
A
ttach
---+!! Conversación de Bar X --- %TOC% --- -Que hay amigo, te lo puse mas fácil, verdad? Un ejercicio muy simple... - Si, pero en los tests que hice y de acuerdo con lo que me enseñaste sobre substitución de parámetros, me pareció que debería hacer otras alteraciones en las funciones que creamos, para dejarlas de uso más general como me dijiste que todas las funciones deberían de ser, quieres ver? - Claro, si te pedí hacerlas es porque estoy con ganas de verte aprender, pero alto! dame un momento! - Mozo! Trae dos, uno sin espuma! - Anda, enseñame lo que hiciste. - Bien, además de lo que me pediste, me fije que el programa que llamaba la función, tendría que tener previamente definida la línea en que sería dado el mensaje y la cantidad de columnas. Lo que hice fue incluir dos líneas - en las cuales emplee sustitución de parámetros - y en caso de que una de estas variables no fuese introducida, la propia función la generaría. La línea del mensaje estaría tres líneas encima del final de la pantalla y el total de columnas sería obtenido por el comando tput cols. Mira como quedó: %TERMINAL_INI% $ cat pergunta.func%OUT_INI% # La función recibe 3 parámetros en el siguiente orden: # $1 - Mensaje a ser dado en pantalla # $2 - Valor a ser aceptado como respuesta default # $3 - Otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, la línea # abajo colocaría en Msj el valor "Acepta? (S/n)" <nop>TotCols=${TotCols:-$(tput cols)} # Si no estaba definido, ahora lo está <nop>LineaMesj=${LineaMesj:-$(($(tput lines)-3))} # Idem Msj="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" <nop>TamMsj=${#Msj} Col=$(((<nop>TotCols - <nop>TamMsj) / 2)) # Para centrar Msj en la línea tput cup $LineaMesj $Col read -n1 -p "$Msj " SN SN=${SN:-$2} # Si vacio coloca default en SN SN=$(echo $SN | tr A-Z a-z) # La salida de SN será en minúscula tput cup $LineaMesj $Col; tput el # Borra msj de pantalla%OUT_FIM% %TERMINAL_FIM% - Me gustó, te anticipaste a lo que te iba a pedir. Solamente para cerrar esta conversación de sustitución de parámetros, fíjate que la legibilidad es horrible, pero la optimización, o sea, la velocidad de ejecución, está óptima. Como las funciones son cosas muy personales, ya que cada uno usa las suyas, y casi no se les da mantenimiento, yo siempre opto por la optimización. - Hoy vamos a salir de aquel aburrimiento que fue nuestra última conversación y volveremos a la lógica saliendo de la memorización, pero te vuelvo a recordar, todo lo que te mostré la otra vez aquí en el Bar, es válido y de gran ayuda, guarda aquellas servilletas que escribimos que tarde o temprano te van a ser muy útiles. ---++ El comando eval - Te voy a dar un problema que dudo que resuelvas: %TERMINAL_INI% $ var1=3 $ var2=var1 %TERMINAL_FIM% - Te dí estas dos variables, y quiero que me digas como puedo, solamente refiriéndome a =$var2=, listar el valor de =$var1= (=3=). - Ah! eso es fácil, es sólo hacer: <verbatim> echo $`echo $var2` </verbatim> - Fíjate que coloqué el echo =$var2= entre comillas (=`=), que de esta forma tendrá prioridad de ejecución y resultará en =var1=, montando =echo$var1= que producirá =3=... - A sí? Entonces ejecutalo a ver si está correcto. %TERMINAL_INI% $ echo $`echo $var2`%OUT_INI% $var1%OUT_FIM% %TERMINAL_FIM% - Eh! Que pasó? Mi razonamiento parecía bastante lógico... - Tu razonamiento realmente fue lógico, el problema es que te olvidaste de una de las primeras cosas de que te hablé aquí en el Bar y voy a repetir. El _Shell_ usa el siguiente orden para resolver una línea de comandos: * Resuelve los redireccionamentos; * Substituye las variables por sus valores; * Resuelve y substituye los meta caracteres; * Pasa la línea ya toda masticada, para ejecución. De esta forma, cuando llegó a la fase de resolución de variables, que como ya dije es anterior a la ejecución, la única variable existente era =$var2= y por eso tu solución produjo como salida =$var1=. El comando =echo= identificó eso como una cadena y no como una variable. Problemas de este tipo son relativamente frecuentes y serían insolubles en caso de que no existiese la instrucción =eval=, cuya sintaxis es: <verbatim> eval cmd </verbatim> Donde =cmd= es una línea de comando cualquiera que se podría inclusive ejecutar directamente en el _prompt_ del terminal. Cuando pones el =eval= al principio, lo que ocurre es que el _Shell_ trata =cmd= como si sus datos fueran parámetros del =eval= y enseguida el =eval= ejecuta la línea recibida, sometiéndola al _Shell_, dando entonces en la práctica dos pasadas en =cmd=. De esta forma si ejecutásemos el comando que propusiste, colocando el =eval= en su comienzo, tendríamos la salida esperada, mira sino: %TERMINAL_INI% $ eval echo $`echo $var2`%OUT_INI% 3%OUT_FIM% %TERMINAL_FIM% Este ejemplo también podría haber sido hecho de la siguiente manera: %TERMINAL_INI% $ eval echo \$$var2%OUT_INI% 3%OUT_FIM% %TERMINAL_FIM% En la primera pasada la barra invertida (=\=) sería retirada y =$var2= resuelto, produciendo =var1=. Para la segunda pasada habría sobrado echo =$var1=, que produciría el resultado esperado. Ahora voy a colocar un comando dentro de =var2=: %TERMINAL_INI% $ var2=ls %TERMINAL_FIM% Voy a ejecutar: %TERMINAL_INI% $ $var2%OUT_INI% 10porpag1.sh alo2.sh listamusica logaute.sh 10porpag2.sh confuso listartista mandamsj.func 10porpag3.sh contpal.sh listartista3 monbg.sh alo1.sh incusu logado%OUT_FIM% %TERMINAL_FIM% Ahora vamos a colocar en =var2= el siguiente: =ls $var1=; y en =var1= vamos a colocar =l*=, veamos: %TERMINAL_INI% $ var2='ls $var1' $ var1='l*' $ $var2%OUT_INI% ls: $var1: No such file or directory%OUT_FIM% $ eval $var2%OUT_INI% listamusica listartista listartista3 logado logaute.sh%OUT_FIM% %TERMINAL_FIM% Nuevamente, al momento de la sustitución de las variables, =$var1= todavía no se había presentado al _Shell_ para ser resuelta, por eso sólo nos queda ejecutar el comando =eval= para dar las dos pasadas necesarias. Una vez un colega de una <a href="http://br.groups.yahoo.com/group/shell-script" target="_blank"><b>excelente lista sobre <i>Shell Script</i></b></a>, presentó una duda: quería hacer un menú que numerase y listase todos los archivos con extensión =.sh= y cuando el operador escogiese una opción, el programa correspondiente sería ejecutado. Mi propuesta fue la siguiente: %TERMINAL_INI% $ cat fazmenu%OUT_INI% #!/bin/bash # # Lista numerando los programas con extensión .sh en # directorio actual y ejecuta el escogido por el operador # clear; i=1 printf "%11s\t%s\n\n" Opción Programa CASE='case $opt in' for arq in *.sh do printf "\t%03d\t%s\n" $i $arq CASE="$CASE "$(printf "%03d)\t %s;;" $i $arq) i=$((i+1)) done CASE="$CASE *) . error;; esac" read -n3 -p "Introduce la opción deseada: " opt echo eval "$CASE"%OUT_FIM% %TERMINAL_FIM% Parece complicado porque usé mucho el =printf= para formatear la pantalla, pero es bastante simple, vamos a entenderlo: el primer =printf= fue colocado para hacer el encabezado y en seguida comencé a montar dinámicamente la variable =$CASE=, sobre la cual al final será hecho un =eval= para la ejecución del programa escogido. Observa sin embargo que dentro del _loop_ del =for= existen dos =printf=: el primero sirve para formatear la pantalla y el segundo para montar el =case= (si antes del comando =read= colocas una línea =echo "$CASE"=, verás que el comando =case= montado dentro de la variable está todo indentado. Una pasada, verdad? :). En la salida del =for=, fue agregada una línea a la variable =$CASE=, para que en el caso de que se haga una opción no válida, sea ejecutada una función externa para dar mensajes de error. Vamos a ejecutarlo para ver la salida generada: %TERMINAL_INI% $ fazmenu.sh%OUT_INI% Opción Programa 001 10porpag1.sh 002 10porpag2.sh 003 10porpag3.sh 004 alo1.sh 005 alo2.sh 006 contpal.sh 007 fazmenu.sh 008 logaute.sh 009 monbg.sh 010 readpipe.sh 011 redirread.sh Introduce la opción deseada:%OUT_FIM% %TERMINAL_FIM% En este programa sería interesante tener una opción de escape, y para eso sería necesario la inclusión de una línea después del _loop_ de montaje de la pantalla y alterar la línea en la cual hacemos la atribución final del valor de la variable =$CASE=. Veamos como quedaría: %TERMINAL_INI% $ cat fazmenu%OUT_INI% #!/bin/bash # # Lista numerando los programas con extensión .sh en # directorio actual y ejecuta el escogido por el operador # clear; i=1 printf "%11s\t%s\n\n" Opción Programa CASE='case $opt in' for arq in *.sh do printf "\t%03d\t%s\n" $i $arq CASE="$CASE "$(printf "%03d)\t %s;;" $i $arq) i=$((i+1)) done printf "\t%d\t%s\n\n" 999 "Fin del programa" # línea incluida CASE="$CASE 999) exit;; # línea alterada *) ./error;; esac" read -n3 -p "Introduce la opción deseada: " opt echo eval "$CASE"%OUT_FIM% %TERMINAL_FIM% ---++ Señales de Procesos Existe en Linux una cosa llamada señal (_signal_). Existen diversas señales que pueden ser mandadas para (o generados por) procesos en ejecución. Vamos de aqui en adelante a dar una ojeada a las señales enviadas hacia los procesos y más adelante vamos a dar una pasada rápida por las señales generados por procesos. ---+++ señales asesinas Para mandar una señal a un proceso, usamos normalmente el comando =kill=, cuya sintáxis es: <verbatim> kill -sig PID </verbatim> Donde =PID= es el identificador del processo (_<kbd>P</kbd>rocess <kbd>ID</kbd>entification_ o _<kbd>P</kbd>rocess <kbd>ID</kbd>_). Además del comando =kill=, algunas secuencias de teclas también pueden generar =sig=. La tabla siguiente muestra las señales más importantes para monitorear: <center> %TABLE{ databg="#ffffff" headerrows="1" }% | *Señales Más Importantes* ||| | <b>Señal</b> || <b> Generado por:</b> | | 0 | EXIT | Fin normal de programa | | 1 | SIGHUP | Cuando recibe un kill -HUP | | 2 | SIGINT | Interrupción por teclado (<CTRL+C>) | | 3 | SIGQUIT | Interrupción por teclado (<CTRL+\>) | | 15 | SIGTERM | Cuando recibe un kill o kill -TERM | </center> Además de estas señales, existe el tan abusado =-9= o =SIGKILL= que, para el proceso que lo está recibiendo, equivale a meter el dedo en el botón de apagar el computador, lo que es altamente indeseable ya que muchos programas necesitan "limpiar el medio campo" a su término. Si el final ocurre de forma prevista, o sea si tiene un final normal, es muy fácil de hacer esta limpeza, sin embargo si el programa tiene un final brusco pueden ocurrir muchas cosas: * Es posible que en un determinado espacio de tiempo, el computador esté lleno de archivos de trabajo inútiles * El procesador podrá quedar lleno de procesos _zombies_ y _defuncts_ generados por procesos hijos que perdieron los procesos padres; * Es necesario liberar _sockets_ abiertos para no dejar los clientes congelados; * Tus bancos de datos podrán quedar corruptos porque los sistemas gestores de bancos de datos necesitan de un tiempo para grabar sus _buffers_ en disco (_commit_). En fin, existen mil razones para no usar un =kill= con la señal =-9= y para monitorizar las terminaciones anormales de programas. ---+++ El trap no atrapa Para hacer el control de procesos descripto antes, existe el comando =trap= cuya sintáxis es: <verbatim> trap "cmd1; cmd2; cmdn" S1 S2 ... SN </verbatim> o <verbatim> trap 'cmd1; cmd2; cmdn' S1 S2 ... SN </verbatim> Donde los comandos =cmd1=, =cmd2=, =cmdn= serán ejecutados en caso de que el programa reciba las señales =S1 S2= ... =SN=. Las comillas (") o los apóstrofes (') sólo son necesarias en el caso de que el =trap= posea más de un comando =cmd= asociado. Cada uno de los =cmd= puede también ser una función interna, una externa u otro _script_. Para entender el uso de las comillas (") y los apóstrofes (') vamos a recurrir a un ejemplo que trata un fragmento de un _script_ que hace un =ftp= hacia una máquina remota (=$RemoComp=), en la cual el usuário es =$Fulano=, su contraseña es =$Secreto= y va a transmitir el archivo contenido en =$Arq=. Supon todavia que estas cuatro variables fueron recibidas en una rutina anterior de lectura y que este _script_ es muy usado por diversas pesonas de la instalación. Veamos este trozo del código: <verbatim> ftp -ivn $RemoComp << FimFTP >> /tmp/$$ 2>> /tmp/$$ user $Fulano $Secreto binary get $Arq FimFTP </verbatim> Observa que, tanto las salidas de los diálogos del =ftp=, como los errores encontrados, están siendo redireccionados para =/tmp/$$=, lo que es una construcción bastante normal para archivos temporarios usados en _scripts_ con más de un usuário, porque =$$= es la variable que contiene el número de proceso (=PID=), que es único, y con este tipo de construcción se evita que dos o más usuários disputen la posesión y los derechos sobre el archivo. En el caso de que este =ftp= sea interrumpido por un =kill= o un =<CTRL+C>=, con toda seguridad dejará basura en el disco. Es exactamente esta la forma más frecuente de usar el comando =trap=. Como esto es un trozo de un _script_, debemos hacer, al empezar y como uno de sus primeros comandos: <verbatim> trap "rm -f /tmp/$$ ; exit" 0 1 2 3 15 </verbatim> Así en el caso de que hubiese una interrupción brusca (señales =1=, =2=, =3= o =15=), antes de que el programa finalize (en el =exit= dentro del comando =trap=), o un fin normal (señal =0=), el archivo =/tmp/$$= seria borrado del disco. En el caso de que en la línea de comandos del =trap= no tuviese la instrucción =exit=, al final de la ejecución de esta línea el flujo del programa volvería al punto en que estaba cuando recibió la señal que originó la ejecución de este =trap=. Este =trap= podria ser subdividido, quedando de la siguiente forma: <verbatim> trap "rm -f /tmp/$$" 0 trap "exit" 1 2 3 15 </verbatim> Así al recibir una de las señales el programa terminaría, y al terminar, generaría una señal =0=, que borraría el archivo. Si la finalización es normal, la señal también será generada y el =rm= será ejecutado. Observa también que el _Shell_ analiza la línea de comandos, una vez cuando el =trap= es interpretado (y es por eso que es usual colocarlo al inicio del programa) y nuevamente cuando se recibe alguna de las señales listadas. Entonces, en el último ejemplo, el valor de =$$= será sustituído en el momento que el comando =trap= es leído por primera vez, ya que las comillas (="=) no protegen el signo de pesos (=$=) de la interpretación del _Shell_. Si deseas que la sustitución sea realizada solamente en el momento de ser recibida la señal, el comando debería estar colocado entre apóstrofes (='=). Así, en la primera interpretación del =trap=, el _Shell_ no vería el signo de pesos (=$=), sin embargo los apóstrofes (='=) serian retirados y finalmente el _Shell_ podría sustituir el valor de la variable. En este caso, la línea quedaria de la siguiente manera: <verbatim> trap 'rm -f /tmp/$$ ; exit' 0 1 2 3 15 </verbatim> Suponte dos casos: tu tienes dos _scripts_ que llamaremos =script1=, cuya primera línea será un =trap= y =script2=, siendo este último ejecutado por una llamada del primero, y por ser dos procesos diferentes, tendrán dos =PID= distintos. * 1º Caso: El =ftp= se encuentra en =script1= %BR% En este caso, el argumento del comando =trap= debería estar entre comillas (="=) porque si ocurriese una interrupcción (=<CTRL+C>= o =<CTRL+\>=) en el =script2=, la línea sólo seria interpretada en este momento y el =PID= del =script2= seria diferente del encontrado en =/tmp/$$= (no te olvides que =$$= es la variable que contiene el =PID= del proceso activo); * 2º Caso: El =ftp= anterior se encuentra en =script2= %BR%En este caso, el argumento del comando =trap= debería estar entre apóstrofes (='=), pues en el caso de que la interrupción se diera durante la ejecución del =script1=, el archivo no habría sido creado, en el caso de que ocurriera durante la ejecución del =script2=, el valor de =$$= sería el =PID= de este processo, que coincidiría con el de =/tmp/$$=. Cuando se ejecuta el comando =trap= sin argumentos, lista las señales que están siendo monitoreadas en el ambiente, así como la línea de comando que será ejecutada cuando tales señales sean recibidas. Si la línea de comandos del =trap= es nula (o sea vacía), esto significa que las señales especificadas deben ser ignoradas cuando sean recibidas. Por ejemplo, el comando: <verbatim> trap "" 2 </verbatim> Especifica que la señal de interrupción (=<CTRL+C>=) debe ser ignorada. En ese caso no se desea que la ejecución sea interrumpida. En el último ejemplo fíjate que el primer argumento debe ser especificado para que la señal sea ignorada, y no es equivalente a escribir lo siguiente, cuya finalidad es de retornar la señal =2= a su estado patrón (_default_): <verbatim> trap 2 </verbatim> Si se ignora una señal, todos los _Subshells_ ignoraran esta señal. Por lo tanto, si tu especificas que acción debe ser tomada cuando se reciba una señal, entonces todos los _Subshells_ también tomaran la misma acción cuando reciban esta señal, o sea, las señales son automáticamente exportadas. Para la señal que hemos mostrado (señal =2=), significa que los Subshells serán finalizados. Suponte que ejecutes el comando: <verbatim> trap "" 2 </verbatim> y entonces ejecutes un _Subshell_, que volverá a ejecutar otro _script_ como un _Subshell_. Si se generase una señal de interrupción, esta no tendrá efecto sobre el _Shell_ principal ni sobre los _Subshell_ por él llamados, ya que todos ellos ignorarán la señal. Otra forma de restaurar una señal a su patrón (_default_) es haciendo: <verbatim> trap - señal </verbatim> En _korn shell_ (=ksh=) no existe la opción =-s= del comando =read= para leer una señal. Lo que acostumbramos hacer es usar el comando =stty= con la opción =-echo= que inhibe la escritura en pantalla hasta que se encuentre un =stty echo= para restaurar esta escritura. Entonces, si estamos usando el interprete =ksh=, la lectura de la señal sería hecha de la siguiente forma: <verbatim> echo -n "Señal: " stty -echo read Señal stty echo </verbatim> El problema en este tipo de construcción es que en el caso de que el operador no supiese la señal, probablemente haría un =<CTRL+C>= o un =<CTRL+\>= durante la instrucción =read= para detener el programa y en el caso de que actúe así, cualquier cosa que escribiese no aparecería en la pantalla del terminal. Para evitar que eso pase, lo mejor a hacer es: <verbatim> echo -n "Señal: " trap "stty echo exit" 2 3 stty -echo read Señal stty echo trap 2 3 </verbatim> Para terminar este asunto, abre un terminal gráfico y escribe en el prompt de comando lo siguiente: %TERMINAL_INI% $ trap "echo Cambió el tamaño de la ventana " 28 %TERMINAL_FIM% En seguida, coge el _mouse_ (arghh!!) y arrástralo para variar el tamaño de la ventana actual. Sorprendido? Es el Shell orientado a eventos... :) Uno mas, porque no me puedo resistir... Ahora escribe esto: %TERMINAL_INI% $ trap "echo acabó" 17 %TERMINAL_FIM% En seguida haz: %TERMINAL_INI% $ sleep 3 & %TERMINAL_FIM% Acabas de crear un _subshell_ que dormirá durante tres segundos en _background_. Al final de este tiempo, recibirás un mensaje =acabó=, porque la señal =17= es emitida cada vez que un _subshell_ termina su ejecución. Para volver estas señales a sus opciones por defecto, haz: %TERMINAL_INI% $ trap 17 28 %TERMINAL_FIM% O: %TERMINAL_INI% $ trap - 17 28 %TERMINAL_FIM% Acabamos de ver otras dos señales que no son tan importante como las que vimos anteriormente, pero voy a registrarlas en la tabla siguiente: <center> %TABLE{ databg="#ffffff" headerrows="1" }% | *Señales no Muy Importantes* ||| | <b>Señal</b> || <b> Generada por:</b> | | 17 | SIGCHLD | Fin de un proceso hijo | | 28 | SIGWINCH | Cambio de tamaño de la ventana gráfica | </center> Muy bueno este comando, verdad? Si tu descubres algun caso interesante del uso de señales, por favor informame por e-mail porque es muy rara la literatura sobre el asunto. ---++ Comando getopts El comando =getopts= recupera las opciones y sus argumentos de una lista de parámetros de acuerdo con la sintáxis POSIX.2, o sea, letras (o números) después de un señal de menos (=-=) seguidas o no de un argumento; en el caso de tener solamente letras (o números) se pueden agrupar. Debes usar este comando para "cortar en partes" opciones y argumentos pasados hacia tu _script_. Sintáxis: <verbatim> getopts cadenadeopciones nombre </verbatim> La =cadenadeopciones= debe explicitar una cadena de caracteres con todas las opciones reconocidas por el _script_, así si este reconoce las opciones =-a= =-b= y =-c=, =cadenadeopciones= debe ser =abc=. Si deseas que una opción sea seguida por un argumento, coloca dos puntos (=:=) después de la letra, como en =a:bc=. Ésto le dice al =getopts= que la opción =-a= tiene la forma: <verbatim> -a argumento </verbatim> Normalmente uno o más espacios en blanco separan el parámetro de la opción; al mismo tiempo, =getopts= también manipula parámetros que vienen pegados a la opción como en: <verbatim> -aargumento </verbatim> =cadenadeopciones= no puede contener el signo de interrogación (=?=). El =nombre= constante en la línea de sintaxis anterior, define una variable que cada vez que el comando =getopts= sea ejecutado, recibirá la próxima opción de los parámetros de posición y la colocará en la variable =nombre=. =getopts= coloca un signo de interrogación (=?=) en la variable definida en =nombre= si encuentra una opción no definida en =cadenadeopciones= o si no encuentra el argumento esperado para una determinada opción. Como ya sabemos, cada opción pasada por una línea de comandos tiene un índice numérico, así, la primera opción estará contenida en =$1=, la segunda en =$2=, y así continúa. Cuando el =getopts= obtiene una opción, almacena el índice del próximo parámetro a ser procesado en la variable =OPTIND=. Cuando una opción tiene un argumento asociado (indicado por =:= en =cadenadeopciones=), =getopts= almacena el argumento en la variable =OPTARG=. Si una opción no posee argumento o el argumento esperado no se encontró, la variable =OPTARG= será "matada" (=unset=). El comando termina su ejecución cuando: * Encuentra un parámetro que no comienza por menos (=-=); * El parámetro especial =--= marca el fin de las opciones; * Cuando encuentra un error (por ejemplo, una opción no reconocida). El ejemplo siguiente es meramente didáctico, y sirve para mostrar, en un pequeño fragmento de código, el uso pleno del comando. %TERMINAL_INI% $ cat getoptst.sh%OUT_INI% #!/bin/sh # Ejecute así: # # getoptst.sh -h -Pimpressora arch1 arch2 # # y note que las informaciones de todas las opciones son exhibidas # # La cadena 'P:h' dice que la opción -P es una opción compleja # y requiere de un argumento, y que h es una opción simple que no requiere # argumentos. while getopts 'P:h' OPT_LETRA do echo "getopts hizo la variable OPT_LETRA igual a '$OPT_LETRA'" echo " OPTARG es '$OPTARG'" done used_up=`expr $OPTIND - 1` echo "Ignorando los primeros \$OPTIND-1 = $used_up argumentos" shift $used_up echo "Lo que sobró de la línea de comandos fue '$*'"%OUT_FIM% %TERMINAL_FIM% Para entenderlo mejor, vamos a ejecutarlo como está sugerido en su encabezado: %TERMINAL_INI% $ getoptst.sh -h -Pimpresora arch1 arch2%OUT_INI% getopts hizo la variable OPT_LETRA igual a 'h' OPTARG es '' getopts hizo la variable OPT_LETRA igual a 'P' OPTARG es 'impresora' Ignorando los primeros $OPTIND-1 = 2 argumentos Lo que sobró de la línea de comandos fue 'arch1 arch2'%OUT_FIM% %TERMINAL_FIM% De esta forma, sin tener mucho trabajo, separé todas las opciones con sus respectivos argumentos, dejando solamente los parámetros que fueron pasados por el operador para un tratamiento posterior . Fíjate que si hubiesemos escrito la línea de comando con el argumento (=impresora=) separado de la opción (=-P=), el resultado sería exactamente el mismo, excepto por el =$OPTIND=, ya que en este caso él identifica un conjunto de tres opciones/argumentos y en el anterior solamente dos. Mira esto: %TERMINAL_INI% $ getoptst.sh -h -P impresora arch1 arch2%OUT_INI% getopts hizo la variable OPT_LETRA igual a 'h' OPTARG es '' getopts hizo la variable OPT_LETRA igual a 'P' OPTARG es 'impresora' Ignorando los primeros $OPTIND-1 = 3 argumentos Lo que sobró de la línea de comandos fue 'arch1 arch2'%OUT_FIM% %TERMINAL_FIM% En el ejemplo siguiente, fíjate que si pasamos una opción inválida, la variable =$OPT_LETRA= recibirá un signo de interrogación (=?=) y la =$OPTARG= será "matada" (=unset=). %TERMINAL_INI% $ getoptst.sh -f -Pimpresora arch1 arch2 # La opción �f no es válida%OUT_INI% ./getoptst.sh: illegal option -- f getopts hizo la variable OPT_LETRA igual a '?' OPTARG es '' getopts hizo la variable OPT_LETRA igual a 'P' OPTARG es 'impresora' Ignorando los primeros $OPTIND-1 = 2 argumentos Lo que sobró de la línea de comandos fue 'arch1 arch2'%OUT_FIM% %TERMINAL_FIM% - Dime una cosa: no podrías haber usado un =case= para evitar el =getopts=? - Podría si, pero para que? Los comandos están ahí para ser usados... El ejemplo dado fue didáctico, pero imagina un programa que aceptase muchas opciones y sus parámetros podrían no estar pegados a las opciones, sus opciones también podrían o no estar pegadas, iba a ser un =case= infernal y con=getopts= es sólo seguir los pasos que vimos anteriormente. - Realmente... Viéndolo de esta forma, me parece que tienes razón. Sera porque ya estoy medio cansado con tanta información nueva en mi cabeza. Vamos a tomar la del estribo o todavia quieres explicar alguna particularidad mas del _Shell_? - Ni lo uno ni lo otro, yo también me cansé, pero hoy no voy a tomar la del estribo porque estoy yendo a dar clases en la <nop>UniRIO, que es la primera universidad federal del Brasil que está preparando a sus alumnos del curso de graduación en informática, en el uso del Software Libre. Pero antes te voy a dejar un problema para embarullar tu cabeza: quando tu varías el tamaño de una ventana gráfica, en el centro no aparece dinámicamente en vídeo inverso la cantidad de líneas y columnas? Entonces! Quiero que reproduzcas eso usando el lenguaje _Shell_. - Mozo, traeme rapidito mi cuenta! Voy a contar hasta uno y si no me la trajiste me voy! 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 <a href="mailto:julio.neves@gmail.com?Subject=Dudas Conversas de bar botequim">julio.neves@gmail.com</a>. 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 <a href="mailto:julio.neves@uniriotec.br?Subject=Curso de Shell con Julio Neves">julio.neves@uniriotec.br</a> para informarse. Gracias y hasta la <a href="https://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarConversa011">próxima</a> -- Main.HumbertoPina - 31 Jan 2007
E
dit
|
A
ttach
|
P
rint version
|
H
istory
: r10
<
r9
<
r8
<
r7
<
r6
|
B
acklinks
|
V
iew topic
|
M
ore topic actions
Topic revision: r10 - 24 Feb 2008 - 00:21:26 -
CollonsTorre
TWikiBar
Página Inicial
Últimas alterações
Índice
Procurar
Estatísticas de Uso
Aviso de Atualização
Configurações Gerais
Projeto Gráfico
Mapa do Site
Quem Somos
Registre-se
?
Regras de Formatação
Biblioteca Gráfica
?
Carinhas Gráficas
Webs Wiki-SL
Amadeu
Anapolivre
ArquivoLivre
Arte
BahiaSocial
BeaBa
BibliotecaLivre
Blogs
BrasilDigital
BrasilELivre
BSM
Ccsa
CESL
CoberturaWiki
Cooperativas
Curriculo
DarvinMarosin
DiaD
Dinamicoop
Economia
EconomiaSolidaria
EducacaoLivre
Ekaaty
Emacsbr
ENSL
Fatos
Festival3
Festival4
Flisol
Fmpb
Formatos
Foswikibr
FSM2005
GNOMEBR
GTTemario2004
GTWeb
Guialivre
HDC
Incubus
InkscapeBrasil
Jogos
KdeBR
KSP
LGM
LinuxStokDoc
Livros
Main
Mentores
MHHOB
MinuanoDigital
MoradiaECidadania
OlhosDagua
Olimpo
OLPC
OOPTQ
Papers
PCLivre
PentahoBrasil
Pessoas
Portal
Prefeituras
PSLAL
PSLBA
PSLBancarios
PSLBrasil
PSLGO
PSLMA
PSLMG
PSLMIP
PSLMT
PSLMulheres
PSLPI
PubFisl10
PubFisl7
PubFisl8
PubFisl9
QuilomboDoSopapo
RadioSL
RedeMesh
RedePopular
RobotWars
Sandbox
Saudelivre
Scribus
Sementes
Shakya
SLRJ
SoftwareLivreIrece
SoftwareLivreVS
SoLiSC
SuporteLivre
System
Telecentros
TeseSA
TextoLivre
TV
TWikiBar
TWikiPtbr
UNELivre
UNIMIX
VilaTorres
WebNordeste
WTRD2004
Este Menu
?skin=free
English
Español
Português brasileiro
Copyright © 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