You are here:
Wiki-SL
>
TWikiBar Web
>
TWikiBarConversa001
(27 Aug 2008,
JulioNeves
)
(raw view)
E
dit
A
ttach
---+!! Conversación de Bar - Parte I %TOC% ---++ Diálogo escuchado entre un Linuxer y un empujador de mouse: - Quién es el _Bash_? - El _Bash_ es el hijo mas nuevo de la familia _Shell_. - Espera ahí! Quieres volverme loco? Tenía una duda y ahora me dejas con dos! - No, loco ya lo eras antes de aparecer por aqui. Desde que decidiste usar aquél sistema operativo con el cual tienes que reiniciar tu máquina unas diez veces por dia y no tienes dominio ninguno sobre lo que está pasando en el computador. Pero deja eso de lado, te voy a explicar lo que es el _Shell_ y los componentes de su familia y al final de la explicación me dirás: "Mi Dios del _Shell_! Porque no opté antes por _Linux_?". ---++ El Ambiente Linux Para que entiendas lo que es y como funciona el _Shell_, primero te mostraré como funciona el ambiente en capas de _Linux_. Da una mirada atenta en el gráfico que sigue: <center><img src="%PUBURL%/%WEB%/FreeSkinImagens/grafico.png" alt="Visión del shell en relación al Kernel de Linux" /></center> En este gráfico se ve que la capa de __hardware__ es la mas profunda estando formada por los componentes físicos de tu computador. Envolviendo a ésta, viene la capa del __kernel__ que es el corazón de _Linux_, su núcleo, y es quien hace que el _hardware_ funcione, efectuando su manejo y control. Los *programas* y *comandos* que envuelven el _kernel_, lo utilizan para realizar las tareas especificas para las cuales fueron desarrolladas. Encerrando todo eso viene el __Shell__ que tiene este nombre porque en ingles, _Shell_ significa concha, envoltura, o sea que, queda entre los usuarios y el sistema operativo, de forma que todo lo que interacciona con el sistema operativo, tiene que pasar por su filtro. ---++ El Ambiente _Shell_ Bueno, si para llegar al núcleo de _Linux_, o sea al _kernel_ que es lo que le interesa a cualquier aplicacion, es necesario el filtro del _Shell_, vamos entonces a entender como funciona este, y la forma de sacar el mayor provecho de las innúmerables facilidades que él nos ofrece. El _Linux_ por definición es un sistema *multiusuario* - no podemos nunca olvidar ésto – y para permitir el acesso de determinados usuarios e impedir la entrada de otros, existe un archivo llamado =/etc/passwd= que además de proveer datos para esta función, especie de "guardián de puerta" del _Linux_, también pasa información para el _login_ de aquellos que consiguieron pasar por esta primera barrera. El último campo de sus registros, informa al sistema cual es el_Shell_ que la persona va a recibir cuando se "loguee" (Ajjjjj!!!). %DICA_INI% Cuando dije que el último campo del =/etc/passwd= informa al sistema cual es el _Shell_ que el usuario va a recibir al "loguearse", es para ser interpretado literalmente, o sea, si en este campo de su registro está =prog=, la persona al acceder al sistema recibirá la pantalla de ejecución del programa =prog= y al terminar la ejecución saldrá inmediatamente con un logout. Imagina cuanto podemos aumentar la seguridad con este simples truco. %DICA_FIM% Te acuerdas que te mencioné de la familia _Shell_? Exactamente, vamos a comenzar a entender esto: el _Shell_, que se vale de la imagen de una concha envolviendo el sistema operativo propiamente dicho, es el nombre genérico para tratar los hijos de esta idea que, con el correr de los años de existencia del sistema operativo _Unix_ fueron apareciendo. Actualmente existen diversos “sabores” de _Shell_, entre ellos destaco el *sh* (Bourne Shell), el *ksh* (Korn Shell), *bash* (Bourne Again Shell) y el *csh* (C Shell). ---+++ Una visión rápida em los Principales Sabores de _Shell_ ---++++ Bourne Shell (sh) Desarrollado por Stephen Bourne de la Bell Labs (de AT&T donde también fue desarrollado el _Unix_), este fue durante muchos años el _Shell patrón_ del sistema operativo _Unix_. Es también llamado de _Standard Shell_ por haber sido durante varios años, el único y hasta hoy es el mas utilizado ya que fue transportado para todos los ambientes _Unix_ y distros _Linux_. ---++++ Korn Shell (ksh) Desarrollado por David Korn, también de la _Bell Labs_, es un superconjunto del sh, o sea, posee todas las facilidades del sh y a ellas se agregaron muchas otras. La compatibilidade total con el sh esta atrayendo a muchos usuarios y programadores de _Shell_ para este ambiente. ---++++ Boune Again Shell (bash) Este es el _Shell_ mas moderno y cuyo número de adeptos crece mas en todo el mundo, sea por ser el _Shell default_ de _Linux_, su sistema operativo natural, o sea por su gran diversidad de comandos, que incorpora inclusive diversas instrucciones características del C Shell. ---++++ C Shell (csh) Desarrollado por Bill Joy de la Berkley University es el _Shell_ mas utilizado en ambientes _*BSD_ e _Xenix_. La estrutura de sus comandos es bastante similar al del lenguage C. Su gran pecado fue ignorar la compatibilidad con el sh, partiendo por un camino propio. Además de estos _Shells_ existen otros, pero contigo voy a hablar solamente sobre los tres primeros, tratandolos genéricamente por _Shell_ y señalando las peculiaridades de cada uno que eventualmente tengan. ---+++ Explicando el funcionamento de _Shell_ El _Shell_ es el primer programa al que accedes al "loguearte" en _Linux_. Es él quien va a resolver una cantidad de cosas para no cargar al _kernel_ con tareas repetitivas, aliviandolo para tratar asuntos mas importantes. Como cada usuario posee su propio _Shell_ interponiendose entre él y el _Linux_, es el _Shell_ quien interpreta los comandos que son tecleados y examina sus sintaxis, pasándolos desmenuzados para su ejecución. - Alto ahí, no corra tanto! Ese trabajo de interpretar comandos no tiene nada que ver con intérprete, no es cierto? - Tiene que ver si, la verdad el _Shell_ es un interpretador (o intérprete realmente) que trae consigo un poderoso lenguaje con comandos de alto nivel, que permite la construcción de _loops_ (lazos), tomas de decisión y de almacenamiento de valores en variables, como te voy mostrar ahora. Voy a explicarte las principales tareas que el _Shell_ cumple, por su orden de ejecución. Prestale mucha atención a este orden porque es fundamental para comprender el resto de nuestra conversación. ---++++ Exámen de la Línea de Comandos En este exámen el _Shell_ identifica los caracteres especiales (reservados) que tienen significado para la interpretación de la línea, inmediatamente después verifica si la línea pasada es una asignación o un comando. ---+++++ Asignación Si el _Shell_ encuentra dos campos separados por un símbolo de igual (===) *sin espacios en blanco entre ellos*, identifica esta secuencia como una asignación. Exemplos %TERMINAL_INI% $ ls linux %OUT_INI%linux%OUT_FIM% %TERMINAL_FIM% En este ejemplo el _Shell_ identificó el =ls= como un programa y el _linux_ como un parámetro pasado para el programa =ls=. %TERMINAL_INI% $ valor=1000 %TERMINAL_FIM% En este caso, por no haber espacios en blanco (y así identificamos que el espacio en blanco es un de los caracteres reservados) el _Shell_ identificó una asignación y colocó =1000= en la variable =valor=. %DICA_INI% *Nunca Haga:* %TERMINAL_INI% $ valor = 1000 %OUT_INI%bash: valor: not found%OUT_FIM% %TERMINAL_FIM% Aqui el _Bash_ tomo la palabra valor aislada por espacios en blanco y juzgó que tu habías mandado ejecutar un programa llamado valor, al cual estarías pasando dos parámetros: === e =1000=. %DICA_FIM% ---+++++ Comando Cuando se escribe una línea en el _prompt_ de _Linux_, esta es dividida en pedazos separados por espacios en blanco: el primer pedazo es el nombre del programa y su existencia sera comprobada; identifica en seguida, en este orden: opciones/parámetros, redireccionamentos y variables. Si el programa identificado existe, el _Shell_ verifica los permisos de los archivos involucrados (inclusive el propio programa), dando un señal de error en caso de que tu no estés autorizado a ejecutar esta tarea. ---++++++ Resolución de Redireccionamentos Después de identificar los componentes de la línea que tecleaste, el _Shell_ parte para la resolución de redireccionamentos. El _Shell_ tiene incorporado a su elenco de ventajas lo que llamamos el redireccionamento, que puede ser de entrada (=stdin=), de salida (=stdout=) o de errores (=stderr=), de acuerdo a como te explicaré a continuación. ---++++++ Substitución de variables En este punto, el _Shell_ verifica si las eventuales variables (parámetros comenzados por =$=), encontradas en el campo del comando, están definidas y las substituye por sus valores actuales. ---++++++ Substitución de Meta caracteres Si algún metacaracter (=*=, =?= ou =[]=) es hallado en la línea de comando, es aquí que será substituido por sus posibles valores. Suponiendo que el único archivo que comienza por la letra =n= en su actual directorio sea un directorio llamado =nombregrandeparacaramba=, si tu haces: %TERMINAL_INI% $ cd n* %TERMINAL_FIM% Como hasta aquí quien está trabajando su línea es el _Shell_ y el comando (programa) =cd= todavía no fue ejecutado, el _Shell_ transforma el =n*= en =nombregrandeparacaramba= y el comando =cd= será ejecutado con éxito. ----++++++ Pasa línea de Comando para el kernel Completadas las anteriores tareas, el _Shell_ monta la línea de comandos, ya con todas las substituciones hechas, llama el _kernel_ para ejecutarla en un nuevo _Shell_ (_Shell_ hijo), recibiendo un número de proceso (PID o _<kbd>P</kbd>rocess <kbd>ID</kbd>entification_) y permanece inactivo, durmiendo una siestecita, durante la ejecución del programa. Una vez finalizado este proceso (junto con el _Shell_ hijo), recibe nuevamente el control y, exhibiendo un _prompt_, muestra que está listo para ejecutar otros comandos. ---+++ Descifrando la Piedra de Roseta Para sacarte aquella sensación que tienes cuando ves un _script Shell_, que mas parece una sopa de letras o un jeroglífico, te mostraré los principales caracteres especiales para que puedas salir por ahí como el __Jean-François Champollion__ descifrando la Piedra de Roseta (vale la pena dar una <a href="http://www.google.com.br/search?num=100&hl=pt-BR&q=%22Jean-Fran%C3%A7ois+Champollion%22&btnG=Pesquisar&meta=cr%3DcountryES" target="_blank">"googlada"</a> para descubrir quién es este tipo). ---++++ caracteres que cambian el significado Por eso mismo, cuando deseamos que el _Shell_ *no interprete* un carácter especial, debemos "esconderlo" de él. Eso puede hacerse de tres formas distintas: ---+++++ Apóstrofe o plic (='=) Cuando el _Shell_ ve una cadena de caracteres entre apostrofes (='=), él saca los apostrofes de la cadena y no interpreta su contenido. %TERMINAL_INI% $ ls linux* %OUT_INI%linuxmagazine%OUT_FIM% $ ls 'linux*' %OUT_INI%bash: linux* no such file or directory%OUT_FIM% %TERMINAL_FIM% En el primer caso el _Shell_ "abrió" el asterisco y descubrió el archivo =linuxmagazine= para listar. En el segundo, los apostrofes evitaron la interpretación del _Shell_ y dio la respuesta que no existe el archivo =linux*=. ---+++++ Contrabarra o Barra Invertida (<nop>\) Idéntico a los apostrofes excepto que la barra invertida evita la interpretación del carácter que la sigue solamente. Suponga que accidentalmente has creado un archivo llamado =*= (asterisco) – que algunos sabores de _Unix_ permiten - y deseas eliminarlo. Si tu hicieras: %TERMINAL_INI% $ rm * %TERMINAL_FIM% Tendrías un gran problema, ya que el =rm= borraría todos los archivos del directorio corriente. La mejor forma de hacerlo es: %TERMINAL_INI% $ rm \* %TERMINAL_FIM% De esta forma, el _Shell_ no interpretaría el asterisco, y por consiguiente no haría su abertura Haz la siguiente experiencia científica: %TERMINAL_INI% $ cd /etc $ echo '*' $ echo \* $ echo * %TERMINAL_FIM% Viste la diferencia? Entonces no se precisa explicar mas. ---+++++ Aspas (="=) Exactamente igual a apostrofe excepto que, si la cadena entre aspas contiene un signo de pesos (=$=), un acento invertido (=`=), o una barra invertida (=<nop>\=), estos caracteres serán interpretados por el _Shell_. No debes preocuparte ahora con todo eso, todavía no te di ejemplos del uso de las aspas porque todavía no conoces el signo de pesos (=$=) ni el acento grave (=`=). De aquí en adelante veremos con mucho detalle el uso de estos caracteres especiales, lo mas importante es entender el significado de cada uno. ---++++ caracteres de redireccionamento La mayoría de los comandos tiene una entrada, una salida y puede generar errores. Esta entrada es llamada Entrada Patrón o =stdin= y su _default_ es el teclado del terminal. Análogamente, la salida del comando es llamada Salida Patrón o =stdout= y su _default_ es la pantalla del terminal. Hacia la pantalla también son enviados por _default_ los mensajes de error oriundos del comando, y que en este caso es la llamada Salida de Error Patrón o =stderr=. Veremos ahora como alterar este estado de cosas. Vamos a hacer un programa tartamudo. Para eso haz: %TERMINAL_INI% $ cat %TERMINAL_FIM% El =cat= es una instrucción que lista el contenido del archivo especificado para la Salida Patrón (=stdout=). En el caso que la entrada no esté definida, el espera los datos de la =stdin=. Mira, como yo no especifiqué la entrada, el está esperándola por el teclado (Entrada Patrón) y como tampoco no cité la salida, lo que yo escriba irá hacia la pantalla (Salida Patrón) haciendo de esta forma, como había propuesto un programa tartamudo. Prueba, prueba, el teclado no muerde! ---+++++ Redireccionamento de la Salida Patrón Para especificar una salida de programa usamos el =>= (mayor que) o el =>>= (mayor, mayor) seguido del nombre del archivo al que se desea mandar la salida. Vamos a transformar el programa tartamudo en un editor de textos (que pretensión eh!). :) %TERMINAL_INI% $ cat > Arch %TERMINAL_FIM% El =cat= continua sin tener una entrada especificada, por lo tanto está aguardando que los datos sean escritos, sin embargo su salida está siendo desviada hacia el archivo =Arch=. De esta forma, todo lo que esta siendo escrito está yendo hacia =Arch=, de forma que hicimos el editor de textos mas corto y pobre del planeta. Si ejecutas nuevamente: %TERMINAL_INI% $ cat > Arch %TERMINAL_FIM% Los datos contenidos en =Arch= se perderán, ya que antes del redireccionamento el _Shell_ creará un =Arch= vacio. Para colocar mas informaciones en el final del archivo deberias haber hecho: %TERMINAL_INI% $ cat >> Arch %TERMINAL_FIM% %ATENCION_INI% Como ya te habia dicho, el _Shell_ resuelve la linea y despues manda el comando para su ejecución. Asi, si tu redireccionas la salida de un archivo hacia el mismo, primero el _Shell_ "vacia" este archivo y después manda el comando para su ejecución, y de esta forma acabas de perder el contenido de tu querido archivo. %ATENCION_FIM% Con esto notamos que el =>>= (mayor mayor) sirve para incluir texto al final del archivo. ---+++++ Redireccionamento de la Salida de Error Patrón Así como el _default_ del _Shell_ es recibir los datos del teclado y mandar las salidas hacia la pantalla, los errores también serán enviados hacia la pantalla si tu no especificas hacia donde deverán ser enviados. Para redireccionar los errores usa =2> <nop>SalidaDeError=. Fijate que entre el número =2= y el símbolo de mayor (=>=) no existe espacio en blanco. %ATENCION_INI% Presta atención! No confundas =>>= con =2>=. El primero anexa datos al final de un archivo, en cuanto el segundo redirecciona la Salida de Error Patrón (=stderr=) hacia el archivo que ha sido designado. *Esto es importante!* %ATENCION_FIM% Suponte que durante la ejecución de un _script_ tu puedes, o no (dependiendo del rumbo tomado por la ejecución del programa), haber creado un archivo llamado =/tmp/seraqueexiste$$=. Para no dejar basura en tu disco, al final del _script_ deberías colocar esta línea: %TERMINAL_INI% $ rm /tmp/seraqueexiste$$ %TERMINAL_FIM% En caso de no existir el archivo, seria enviado hacia la pantalla un mensaje de error. Para que eso no ocurra se debe hacer: %TERMINAL_INI% $ rm /tmp/seraqueexiste$$ 2> /dev/null %TERMINAL_FIM% Sobre el ejemplo que acabamos de ver tengo dos consejos a dar: %DICA_INI% *Consejo # 1* El =$$= contiene el PID, o sea, el número de su proceso. Como _Linux_ es multiusuario, es de buenos modales anexar siempre el =$$= a los nombre de los archivos que serán usados por varias personas para que no haya problemas de propriedad, o sea, en caso que nombrases tu archivo simplemente como =seraqueexiste=, el primero que lo usase (creándolo entonces) seria su dueño y todos los otros obtendrian un error cuando intentasen grabar algo en él. %DICA_FIM% Para que hagas un test de la Salida de Error Patrón te voy a dar otro ejemplo, escribe directamente en el _prompt_ del _Shell_: %TERMINAL_INI% $ ls noexiste %OUT_INI%bash: noexiste no such file or directory%OUT_FIM% $ ls noexiste 2> archivodeerrores $ $ cat archivodeerrores %OUT_INI%bash: noexiste no such file or directory%OUT_FIM% %TERMINAL_FIM% En este ejemplo, vimos que cuando hicimos un =ls= en =noexiste=, obtuvimos un mensaje de error. Después, redireccionamos la Salida de Error Patrón hacia =archivodeerros= y executamos el mismo comando, recibiendo solamente el _prompt_ en la pantalla. Cuando listamos el contenido del archivo para el cual fue redireccionada la Salida de Error Patron, vimos que el mensaje de error habia sido almacenado en él. Haz este test. %DICA_INI% *Dica # 2* - Quién es ese tal de =/dev/null=? - En _Unix_ existe un archivo fantasma. Llamase =/dev/null=. Todo lo que es enviado a este archivo desaparece. Se parece a un Agujero Negro. En el caso del ejemplo, como no me interesaba guardar el posible mensaje de error proveniente del comando =rm=, lo redireccioné para este archivo. %DICA_FIM% Es interesante notar que estos caracteres de redireccionamento son acumulativos, o sea, si en el ejemplo anterior hicieramos: %TERMINAL_INI% $ ls noexiste 2>> archivodeerrores %TERMINAL_FIM% el mensaje de error proveniente del =ls= seria añadido al final de =archivodeerrores=. ---+++++ Redireccionamento de la Entrada Patrón Para hacer el redireccionamento de la Entrada Patrón usamos el =<= (menor que). - Y para que sirve eso? - me vas a preguntar. - Déjame darte un ejemplo que vas a entender rapidito. Supone que quieres mandar un =mail= a tu jefe. Para el Jefe queremos lo mejor, no es así? entonces, en lugar de escribir el =mail= dirigiéndolo directamente al _prompt_ de la pantalla de forma de que será imposible la corrección de una frase anterior donde, sin querer, escribiste un "nosotros va", tu editas un archivo con el contenido del mensaje y después de unas quince verificaciones sin constatar errores, decides enviarlo y para eso haces: %TERMINAL_INI% $ mail jefe < archivoconmailparaeljefe %TERMINAL_FIM% Tu jefe reciberá entonces el contenido del =archivoconmailparaeljefe=. Otro tipo de redireccionamento muy loco que el _Shell_ te permite es el llamado __here document__. Es representado por =<<= (menor menor) y sirve para indicar al _Shell_ que el alcance de un comando comenza en la línea siguiente y termina cuando encuentra una línea cuyo contenido sea unicamente la etiqueta que sigue al símbolo =<<=. Observa a continuación el fragmento de un _script_, con una rutina de =ftp=: <verbatim> ftp -ivn hostremoto << fimftp user $Usuario $Seña binary get archivoremoto fimftp </verbatim> En este pedacito de programa tenemos una cantidad de detalles interesantes: * Las opciones que usé para el =ftp= (=-ivn=) sirven para ir listando todo lo que está ocurriendo (=—v= de verbose), para no preguntar si tienes la seguridad de que deseas transmitir cada archivo (=—i= de interactive), y finalmente la opción =—n= sirve para decirle al =ftp= para que no solicite el usuario y su contraseña, pues estos estarán indicados por la instrucción específica (=user=); * Cuando usé el =<< fimftp=, estaba diciendo lo siguiente para el intérprete:%BR%- Mira aqui _Shell_, no hagas nada a partir de aqui hasta encontrar la etiqueta =fimftp=. Tu no entenderias nada, ya que son instrucciones específicas del comando =ftp= y tu no entiendies nada de =ftp=.%BR%Si solo fuera eso, seria simple, pero el mismo ejemplo dá para ver que existen dos variables (=$Usuário= e =$Senha=), que el _Shell_ va a resolver antes del redireccionamento. Sin embargo, la gran ventaja de este tipo de construcción es que ella permite que los comandos también sean interpretados dentro del alcance del _here document_, lo que también contradice lo que acabe de decir. Enseguida explico como funciona esto. No es este el momento todavía, nos faltan herramientas. * El comando =user= es del repertorio de instrucciones del =ftp= y sirve para pasar el usuario y la contraseña, que habian sido leídos en una rutina anterior a ese fragmento de código y colocados respectivamente en las dos variables: =$Usuário= y =$Seña=. * El =binary= es otra instrucción del =ftp=, que sirve para indicar que la transferencia de =archivoremoto= será hecha en modo binario, o sea, el contenido del archivo no será interpretado para saber se está en ASCII, EBCDIC, ... * El =get archivoremoto= le dice al =ftp= que saque ese archivo del =hostremoto= y lo traiga a nuestro host local. Si fuera para mandar el archivo, usariamos el comando =put=. %ATENCION_INI% Un error muy frecuente en el uso de =labels= (como el =fimftp= del ejemplo anterior) es causado por la presencia de espacios en blanco antes o después del mismo. Estate muy atento en relación a esto, por que este tipo de errores causan muchos dolores de cabeza a los programadores, hasta que son detectados. Acuérdate: un =label= que se precie, tiene que tener una linea enterita solamente para él. %ATENCION_FIM% - Está bien, está bien! Ya sé que salí de viaje y entré por los comandos del =ftp=, escapando de nuestro asunto, que es el _Shell_, pero como siempre es bueno aprender algo mas y es raro que las personas estén dispuestas para enseñar... ---++++ Redireccionamento de Comandos Los redireccionamentos que hablamos hasta aqui siempre se referían a archivos, o sea mandaban hacia archivo, recibían de archivo, simulaban archivo local, ... Lo que veremos a partir de ahora, redirecciona la salida de un comando hacia la entrada de otro. Esto es utilísimo y facilita la vida un montón. Su nome es _pipe_ (que en inglés significa tubo, ya que él envía la salida de un comando directamente como por un caño hacia la entrada del otro) y su representación es una barra vertical (=|=). %TERMINAL_INI% $ ls | wc -l %OUT_INI% 21%OUT_FIM% %TERMINAL_FIM% El comando =ls= pasó la lista de archivos para el comando =wc=, que cuando está con la opción =–l= cuenta la cantidad de lineas que recibió. De esta forma, podemos afirmar categóricamente que en mi diretorio existían 21 archivos. %TERMINAL_INI% $ cat /etc/passwd |sort | lp %TERMINAL_FIM% Esta linea de comandos manda la lista del archivo =/etc/passwd= hacia la entrada del comando =sort=. Éste la clasifica y la manda para el =lp= que es el gerente mandamás del _spool_ de impresión. ---++++ Caracteres de Ambiente Cuando quieres priorizar una expresión la colocas entre paréntesis, no es así? Puede ser, a causa de la aritmética es normal que pensemos así. Sin embargo, en _Shell_ lo que prioriza realmente son los acentos graves (=`=) y no los paréntesis. Te voy a dar ejemplos del uso de los acentos graves para que lo entiendas mejor. Si quiero saber cuántos usuarios están "logados" en el computador que administro. Puedo hacer: %TERMINAL_INI% $ who | wc -l %OUT_INI% 8%OUT_FIM% %TERMINAL_FIM% El comando =who= pasa la lista de usuarios conectados al comando =wc –l= que cuenta cuantas lineas recibió y lista la respuesta en la pantalla. Ahora bien, en lugar de tener un ocho suelto en la pantalla, lo que quiero es que esté colocado en medio de una frase. Entonces, para mandar frases hacia la pantalla usamos el comando =echo=, veamos entonces como queda: %TERMINAL_INI% $ echo "Existen who | wc -l usuarios conectados" %OUT_INI%Existen who | wc -l usuarios conectados%OUT_FIM% %TERMINAL_FIM% Epa! Que pasó?, no funcionó! Exactamente, no funcionó y no fue por causa de las aspas que coloqué, sino porque tendria que haber ejecutado el =who | wc -l= antes del =echo=. Para resolver este problema, tengo que priorizar esta segunda parte del comando com el uso de los acentos graves, haciéndolo de la siguiente forma: %TERMINAL_INI% $ echo "Existen `who | wc -l` usuarios conectados" %OUT_INI%Existen 8 usuarios conectados%OUT_FIM% %TERMINAL_FIM% Para eliminar esa cantidad de espacios en blancos antes del =8= que el =wc -l= produjo, basta sacar las aspas. Así: %TERMINAL_INI% $ echo Existen `who | wc -l` usuarios conectados %OUT_INI%Existen 8 usuarios conectados%OUT_FIM% %TERMINAL_FIM% Como dije antes, las aspas protejen todo lo que está dentro de sus límites, de la interpretación del _Shell_. Como para el _Shell_ basta un espacio en blanco como separador, esa cantidad de espacios será cambiada por un único espacio, después de haber retirado las aspas (económico, eh?). Antes de hablar sobre el uso de los paréntesis déjame explicar rapidamente acerca del uso del punto y coma (=;=). Cuando estés en el _Shell_, siempre debes dar un comando en cada linea. Para agrupar comandos en una misma línea tenemos que separarlos por punto y coma. De esta forma: %TERMINAL_INI% $ pwd ; cd /etc; pwd; cd -; pwd %OUT_INI%/home/midir /etc/ /home/midir%OUT_FIM% %TERMINAL_FIM% En este ejemplo, listé el nombre del directorio corriente con el comando =pwd=, me cambié para el directorio =/etc=, nuevamente listé el nombre del directorio y finalmente volví para el directorio donde estaba anteriormente (=cd -=), listando su nombre. Note que coloqué el punto y coma (=;=) de todas las formas posibles para mostrar que no importa si existen espacios en blanco antes o después de este caracter. Finalmente veamos el caso de los paréntesis. Observa el caso siguiente, muy parecido al ejemplo anterior: %TERMINAL_INI% $ (pwd ; cd /etc ; pwd;)%OUT_INI% /home/midir /etc/%OUT_FIM% $ pwd%OUT_INI% /home/midir%OUT_FIM% %TERMINAL_FIM% - Qué es eso, por amor del _Shell_!? Yo estaba en =/home/midir=, me cambié para el =/etc=, verifiqué que estaba en ese directorio con el =pwd= seguiente y cuando el agrupamiento de comandos terminó, vi que continuaba en el =/home/midir=, como si nunca hubiera salido de alli! - Ah! Será que es cosa de magos? - No me confundas, amigo!! No es nada de eso! Lo interesante del uso de paréntesis es que se llama a un nuevo _Shell_ para ejecutar los comandos que están en su interior. De esta forma, realmente fuimos para el directorio =/etc=, sin embargo cuando todos los comandos dentro de los paréntesis fueron ejecutados, el nuevo _Shell_ que estaba en el directorio =/etc= murió y volvimos al _Shell_ anterior cuyo directorio corriente era =/home/midir=. Haz otras pruebas usando =cd=, y =ls= para que dejes este concepto bien cimentado. Ahora que ya conocemos estos conceptos observemos este ejemplo que sigue: %TERMINAL_INI% $ mail apoyo << FIM > Hola apoyo, hoy a las ‘date "+%H:%M"‘ > ocurrió nuevamente aquel problema > que ya habia informado por > teléfono. De acuerdo con su pedido > ahí va una lista de los archivos > del directorio: > ‘ls —l‘ > Abrazos a todos. > FIM %TERMINAL_FIM% Finalmente ahora tenemos el conocimiento necesario para mostrar lo que habiamos conversado sobre __here document__. Los comandos entre acentos graves (=`=) tendrán prioridad y por tanto el _Shell_ los ejecutará antes de la instrucción =mail=. Cuando el apoyo reciba el _e-mail_, verá que los comandos =date= y =ls= fueron ejecutados inmediatamente antes del comando =mail=, recibiendo entonces una fotografía del ambiente en el momento en que la correspondencia fue enviada. El _prompt_ primario _default_ del _Shell_, como vimos, es el símbolo de pesos (=$=), sin embargo el _Shell_ usa el concepto de _prompt_ secundario, o de continuación de comando, que es enviado para la pantalla cuando hay un quiebro de linea y la instrucción no terminó. Ese _prompt_, es representado por un símbolo de mayor (=>=), que vemos precediendo a partir de la 2ª linea del ejemplo. Para finalizar y mezclarlo todo, debo decir que existe una construcción mas moderna que viene siendo utilizada como forma de priorizar la ejecución de comandos, como hacen los acentos graves (=`=). Son las construcciones del tipo =$(cmd)=, donde =cmd= es un (o varios) comando(s) que será(n) ejecutado(s) con prioridad en su contexto. De esta forma, el uso de acentos graves(=`=) o construcciones del tipo =$(cmd)= sirven para el mismo fin, sin embargo para quien trabaja con sistemas operativos de diversos fabricantes (multiplataforma), aconsejo el uso de los acentos invertidos, ya que el =$(cmd)= no fue trasladado para todos los sabores de _Shell_. Aqui dentro del Bar, usaré las dos formas, indistintamente. Veamos nuevamente el ejemplo dado para los acentos invertidos, ahora con una nueva visión: %TERMINAL_INI% $ echo Existen $(who | grep wc -l) usuarios conectados %OUT_INI%Existen 8 usuarios conectados%OUT_FIM% %TERMINAL_FIM% Mira este caso: %TERMINAL_INI% $ Archs=ls $ echo $Archs %OUT_INI%ls%OUT_FIM% %TERMINAL_FIM% En este ejemplo, hice una asignación (=<nop>==) y ejecuté una instrucción. Lo que quería era que la variable =$Archs=, recibiese la salida del comando =ls=. Como las instrucciones de un _script_ son interpretadas de arriba hacia abajo y de izquierda a derecha, la asignación fue hecha antes de la ejecución del =ls=. Para hacer lo que deseamos es necesario que le dé prioridad a la ejecución de este comando en perjuicio de la asignación y esto puede ser realizado de cualquiera de las maneras siguientes: %TERMINAL_INI% $ Archs=`ls` %TERMINAL_FIM% o: %TERMINAL_INI% $ Archs=$(ls) %TERMINAL_FIM% Para cerrar este asunto con broche de oro, vamos a ver un último ejemplo. Digamos que quiero colocar dentro de la variable =$Archs= la lista detallada (=ls -l=) de todos los archivos comenzados por =arch= y seguidos de un único caracter (=?=). Para eso deberia hacer: %TERMINAL_INI% $ Archs=$(ls -l arch?) %TERMINAL_FIM% o: %TERMINAL_INI% $ Achs=`ls -l arch?` %TERMINAL_FIM% Sin embargo, ve esto: %TERMINAL_INI% $ echo $Archs %OUT_INI%-rw-r--r-- 1 jneves jneves 19 May 24 19:41 arch1 -rw-r--r-- 1 jneves jneves 23 May 24 19:43 arch2 -rw-r--r-- 1 jneves jneves 1866 Jan 22 2003 archl%OUT_FIM% %TERMINAL_FIM% - Caramba! salió todo junto! - Eso mismo, como ya te dije, si tu dejas que el _Shell_ “vea” los espacios en blanco, siempre que haya diversos espacios juntos, estos serán cambiados por uno solo. Para que la lista salga bien bonita, es necesario proteger la variable de la interpretación de _Shell_, así: %TERMINAL_INI% $ echo "$Archs" %OUT_INI%-rw-r--r-- 1 jneves jneves 19 May 24 19:41 arch1 -rw-r--r-- 1 jneves jneves 23 May 24 19:43 arch2 -rw-r--r-- 1 jneves jneves 1866 Jan 22 2003 archl%OUT_FIM% %TERMINAL_FIM% - Y ahora amigo, ve practicando esos ejemplos, porque, cuando nos encontremos nuevamente, te voy a explicar una serie de instrucciones típicas de programación _Shell_. Chau! Ahh! Solamente una cosita mas que me estaba olvidando de decirte. En _Shell_, el símbolo (=#=) es usado cuando deseamos hacer un comentario. %TERMINAL_INI% $ exit # pídele la cuenta al mozo :( %TERMINAL_FIM% Cualquer duda o falta de compañia para tomar una cerveza o incluso 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én para mandar mi aviso publicitario: puedes decirle a los amigos que quien quiera hacer un curso nota diez de programación en _Shell_ que mande un e-mail para <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/TWikiBarConversa002">próxima</a> -- Main.HumbertoPina - 01 Sep 2006
E
dit
|
A
ttach
|
P
rint version
|
H
istory
: r15
<
r14
<
r13
<
r12
<
r11
|
B
acklinks
|
V
iew topic
|
M
ore topic actions
Topic revision: r15 - 27 Aug 2008 - 22:28:58 -
JulioNeves
TWikiBar.TWikiBarConversa001 moved from TWikiBar.ConversaBar001 on 01 Sep 2006 - 16:50 by
JarbasJunior
-
put it back
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