You are here:
Wiki-SL
>
TWikiBar Web
>
TWikiBarConversa011
(24 Feb 2008,
CollonsTorre
)
(raw view)
E
dit
A
ttach
---+!! Conversación de Bar parte XI --- %TOC% --- - Ei!, como va amigo, todo bien? - Más o menos.. te acuerdas que me pediste que hiciera un programa que cuando el tamaño de la pantalla variase, en el centro apareciese dinamicamente y en vídeo inverso, la cantidad de líneas y columnas, de la misma forma que el Linux hace normalmente?. Bueno, lo hice, pero la apariencia no quedó igual. - No estoy preocupado por la apariencia, lo que yo quería es que ejercitases lo que aprendimos. Déjame ver lo que hiciste. %TERMINAL_INI% $ cat tamtela.sh%OUT_INI% #!/bin/bash # # Colocar en el centro de la pantalla, con vídeo inverso, # una cantidad de columnas y lineas # cuando el tamaño de la pantalla es alterado. # trap Muda 28 # 28 = señal generada por el cambio de tamaño # de la pantalla y Muda es la función que hace eso. Bold=$(tput bold) # Negrita, modo de énfasis Rev=$(tput rev) # Modo de vídeo inverso Norm=$(tput sgr0) # Restaura la pantalla al valor por defecto Muda () { clear Cols=$(tput cols) Lins=$(tput lines) tput cup $(($Lins / 2)) $(((Cols - 7) / 2)) # Centro de la pantalla echo $Bold$Rev$Cols X $Lins$Norm } clear read -n1 -p "Cambie el tamaño de la pantalla o teclee algo para terminar"%OUT_FIM% %TERMINAL_FIM% - Perfecto!, que se joda la apariencia, después te enseño otras formas de mejorarlo, lo que vale es el programa, está funcionando y esta todo optimizado. - Pero perdí la mayor parte del tiempo intentando descubrir como aumentar el tamaño de la fuente.- ... - Deja eso para otro día, hoy vamos a ver unas cosas bastante interesantes y útiles.. ---++ Named Pipes Otro tipo de pipes es el "named pipes", que también es llamado por =FIFO=. =FIFO= es un acrónimo de _<kbd>F</kbd>irst <kbd>I</kbd>n <kbd>F</kbd>irst <kbd>O</kbd>ut_, que se refiere a la propiedad de que los bytes salen con el mismo orden que entran. El "name" en named pipe es en verdad el nombre de un archivo. Los archivos tipo =named pipe= son mostrados por el comando "ls" como cualquier otro, con pocas diferencias, mira: %TERMINAL_INI% $ ls -l pipe1%OUT_INI% prw-r-r-- 1 julio dipao 0 Jan 22 23:11 pipe1|%OUT_FIM% %TERMINAL_FIM% La =p= en la columna del lado izquierdo indica que pipe1 es un =named pipe=. El resto de los bits de control de permisos, que se pueden leer o grabar al pipe, funcionan como un archivo normal. En los sistemas mas modernos una barra vertical (=|=) colocada al final del nombre del archivo, es otra pista y en los sistemas _LINUX_, donde la opción de color esta habilitada, el nombre del archivo se escribe en rojo por defecto. En los sistemas mas antiguos, los =named pipes= son creados por el programa =mknod=, normalmente situado en el directorio =/etc=. En los sistemas mas modernos, la misma tarea es hecha por =mkfifo=. EL programa =mkfifo= recibe uno o mas nombres como argumento y crea _pipes_ con esos nombres. Por ejemplo , para crear un =named pipe= con nombre =pipe1= haz: %TERMINAL_INI% $ mkfifo pipe1 %TERMINAL_FIM% Como siempre la mejor forma de mostrar que algo funciona es dando ejemplos. Suponga que hayamos creado el =named pipe= mostrado anteriormente. Vamos ahora a trabajar con dos secciones o dos consolas virtuales o una de cada una. En una de ellas haz: %TERMINAL_INI% $ ls -l > pipe1 %TERMINAL_FIM% en la otra haz: %TERMINAL_INI% $ cat < pipe1 %TERMINAL_FIM% _Voilá_! La salida del comando ejecutado en la primera consola fue mostrada en la segunda. Fíjate que el orden en que los comandos ocurrieron no importa. Si prestaste atención, viste que el primer comando ejecutado parecía estar "colgado". Esto sucede por que la otra punta del _pipe_ todavía no estaba conectada, y entonces el sistema operativo suspendió el primer proceso hasta que el segundo proceso "abriera" el _pipe. Para que un proceso que usa el _pipe_ no quede en modo _wait_, es necesario que en una punta del _pipe_ tenga un proceso "que habla" y en el otro un proceso " que escucha" y en el ejemplo que dimos , el =ls= era el que hablaba y el =cat= era el que escuchaba.- Una aplicación muy útil de los =named pipes= es permitir que programas sin ninguna relación se puedan comunicar entre sí, los =named pipes= también son usados para sincronizar procesos, ya que en un determinado punto puedes colocar un proceso para "escuchar" o "hablar" en un determinado =named pipe= y solo saldrá de allí , si otro proceso "habla" o "escucha" en aquel _pipe_. Viste que el uso de esta herramienta es ideal para sincronizar los procesos y para bloquear archivos y poder evitar así perdida o corrupción de información debido a actualizaciones simultáneas (concurrencia). Veamos ejemplos para ilustrar estos casos. ---+++ Sincronización de procesos. Imagina que lanzas paralelamente dos programas (procesos), los diagramas de bloque de sus rutinas son como muestra la siguiente figura: <center> <img src="%PUBURL%/%WEB%/FreeSkinImagens/imagem.GIF" alt="Gráfico del Named Pipe" /> </center> Los dos procesos son lanzados en paralelo y en el =BLOCO1= del =Programa1= las tres clasificaciones son lanzadas de la siguiente manera: <verbatim> for Arq in BigFile1 BigFile2 BigFile3 do if sort $Arq then Manda=va else Manda=pare break fi done echo $Manda > pipe1 [ $Manda = pare ] && { echo Error durante la clasificación de los archivos exit 1 } ... </verbatim> De esta forma, el comando =if= verifica cada clasificación que está siendo efectuada. En caso de que ocurra un problema, las clasificaciones siguientes serán abortadas, un mensaje conteniendo la cadena =pare= es enviada por el =pipe1= y el =programa1= es finalizado con un fin anormal. Mientras el =Programa1= ejecutaba su primero bloque (las clasificaciones) el =Programa2= ejecutaba su bloque =BLOCO1=, procesando sus rutinas de apertura y menú paralelamente al =Programa1=, ganando de esta forma un buen intervalo de tiempo. El fragmento del código del =Programa2= que vemos a continuación, muestra la transición del =BLOCO1= hacia el =BLOCO2=: <verbatim> OK=`cat pipe1` if [ $OK = va ] then ... Rutina de impresión ... else # Recibí "pare" en OK exit 1 fi </verbatim> Después de la ejecución del primer bloque , el =Programa2= pasará a "escuchar" el =pipe1=, quedando parado hasta que las clasificaciones del =Programa1= terminen, comprobando a continuación el mensaje pasado por el =pipe1= para decidir si los archivos están preparados para ser impresos , o si el programa debería terminarse. De esta forma es posible lanzar programas de forma sincronizada y no sincronizada cuando es necesario, ganando bastante tiempo de procesamiento. ---+++ Bloqueo de archivos Supón que escribes una CGI (_<kbd>C</kbd>ommon <kbd>G</kbd>ateway <kbd>I</kbd>nterface_) en _Shell_ para contar cuantos _hits_ recibe una determinada URL y la rutina del contador es la siguiente: <verbatim> Hits="$(cat page.hits 2> /dev/null)" || Hits=0 echo $((Hits=Hits++)) > page.hits </verbatim> De esa forma si la página recibe dos o mas accesos concurrentes, uno o mas podrá(n) perderse, basta que el segundo acceso sea hecho después de una lectura del archivo =page-hits= y antes de su grabación, es decir, basta que el segundo acceso sea hecho después de que el primero haya ejecutado la primer línea del _script_y antes de ejecutar la segunda. Entonces que hacemos? Para resolver el problema de concurrencia vamos a utilizar un =named pipe=. Creamos el siguiente _scritp_ que será el daemon que recibirá la pagina en nuestro site que necesita de un contador. %TERMINAL_INI% $ cat contahits.sh%OUT_INI% #!/bin/bash PIPE="/tmp/pipe_contador" # archivo llamado pipe # dir donde serán colocados los archivos contadores de cada pagina DIR="/var/www/contador" [ -p "$PIPE" ] || mkfifo "$PIPE" while : do for URL in $(cat < $PIPE) do FILE="$DIR/$(echo $URL | sed 's,.*/,,')" # OBS1: en el sed arriba, como precisaba buscar # una barra,usamos coma como separador. # OBS2: cuando rodar como daemon comente la próxima línea echo "arquivo = $FILE" n="$(cat $FILE 2> /dev/null)" || n=0 echo $((n=n+1)) > "$FILE" done done%OUT_FIM% %TERMINAL_FIM% Como solamente este script modifica los archivos, no existe problema de concurrencia Este script será un _daemon_, esto es, correrá en _background_. Cuando una página sufre un acceso, el script escribirá su URL en el archivo del _pipe_. Para probarlo, ejecuta este comando: <verbatim> echo "test_pagina.html" > /tmp/pipe_contador </verbatim> Para evitar errores, en cada página que quisiéramos agregar el contador añadiriamos la siguiente linea: <verbatim> <!--#exec cmd="echo $REQUEST_URI > /tmp/pipe_contador"--> </verbatim> Observa que la variable =$REQUEST_URI= contiene el nombre del archivo que el navegador (_browser_)pidió. Este último ejemplo ,es fruto de una idea que intercambié con un amigo y maestro en _Shell_ , Thobias Salazar Trevisan que escribió el _script_ y lo colocó en su excelente URL. Aconsejo a todos que los que quieren aprender _Shell_ <a href="http://www.google.com.br/search?hl=pt-BR&q=%22thobias+salazar+trevisan%22+%22Seja+bem-vindo%22&btnG=Pesquisar&meta=lr%3Dlang_pt" target="_blank">que le echen un vistazo y la incluyan en sus favoritos</a>. Aja! Pensaste que el asunto sobre los =named pipes= estaba terminado? Pues estabas engañado. A continuación te voy a mostrar un uso diferente de ellos. ---+++ Substitución de procesos Acabo de mostrarte un montón de recetas sobre los =named pipes= . Ahora te voy a mostrar que el _Shell_ también usa los =named pipes= de una manera bastante singular, que es la sustitución de procesos (_process substitution_). Una sustitución de procesos ocurre cuando dentro de un _pipeline de comando_ pones un comando entre paréntesis y un =<= o un =>= unido al paréntesis de la izquierda. Por ejemplo, tecleando el comando: %TERMINAL_INI% $ cat <(ls -l) %TERMINAL_FIM% Resultará que el comando =ls -l= ejecutado en un _subshell_ como es normal (por estar entre paréntesis), redireccionará la salida a un =named pipe= temporal, que el _Shell_ crea, usa y luego elimina. Entonces el =cat= tendrá un nombre de archivo válido para leer (que será este =named pipe= y cuyo dispositivo lógico asociado es =/dev/fd/63=), y tendremos la misma salida que la generada por la del =ls -l=, pero dando uno o mas pasos de lo usual, y esto es mas costoso para el computador. Como podremos constatar esto? Fácil .. Mira el siguiente comando: %TERMINAL_INI% $ ls -l >(cat) l-wx------ 1 jneves jneves 64 Aug 27 12:26 /dev/fd/63 -> pipe:[7050] %TERMINAL_FIM% Y... Realmente es un =named pipe=. Debes estar pensando que esto es una locura _nerd_ , no? Entonces supongamos que tenes 2 directorios: =dir= y =dir.bkp= , y deseas saber si los dos son iguales ( aquella vieja duda: estará mi _backup_ actualizado? ). Basta comparar los dos archivos de los directorios con el comando =cmp=, haciendo: %TERMINAL_INI% $ cmp <(cat dir/*) <(cat dir.bkp/*) || echo backup desactualizado! %TERMINAL_FIM% o, mejor todavía: %TERMINAL_INI% $ cmp <(cat dir/*) <(cat dir.bkp/*) >/dev/null || echo backup desactualizado! %TERMINAL_FIM% De la última forma, la comparación fue efectuada en todas las líneas de todos los archivos de ambos directorios. Para acelerar el proceso, podríamos comparar solamente el listado largo de ambos en los directorios, pues cualquier modificación que un archivo sufra, es mostrado como alteración de la fecha/hora y/o del tamaño del archivo. Mira como quedaría: %TERMINAL_INI% $ cmp <(ls -l dir) <(ls -l dir.bkp) >/dev/null || echo backup desactualizado! %TERMINAL_FIM% Este es un ejemplo meramente didáctico, pues son tantos los comando que producen mas de una línea de salida que sirve como guia para otros. Quiero generar una lista de mis archivos, numerados y al final dar el total de archivos del directorio actual: <verbatim> while read arq do ((i++)) # así no es necesario inicializar i echo "$i: $arq" done < <(ls) echo "En el directório corriente (`pwd`) existen $i archivos" </verbatim> Está bien, yo sé que existen otras formas de ejecutar la misma tarea. Usando el comando =while=. La forma mas común de resolver este problema sería: <verbatim> ls | while read arq do ((i++)) # así no es necesario inicializar i echo "$i: $arq" done echo "En el directório corriente (`pwd`) existen $i archivos" </verbatim> Cuando ejecutase el _script_, parecería que esta todo ok, sin embargo en el comando =echo= después del =none=, vas a ver que el valor de =$i= se perdió. Esto se debe al hecho de que esta variable esta siendo incrementada en un _subshell_ creado por el _pipe_ (=|=) y que termina con el comando =done=, llevándose con él todas las variables creadas en su interior y las alteraciones hechas en todas la variables, inclusive las creadas externamente. Solamente para mostrarte que una variable creada fuera del subshell y alterada en su interior, pierde las alteraciones hechas al final, ejecuta el _script_ siguiente: <verbatim> #!/bin/bash LIST="" # Creada en el shell principal ls | while read FILE # Inicio del subshell do LIST="$FILE $LIST" # Alterada dentro del subshell done # Fin del subshell echo :$LIST: </verbatim> Al final de la ejecución vas a ver que aparecerán apenas dos puntos (=::=). Pero en el inicio de este ejemplo te dije que era meramente didáctico, ya que existen formas mejores de hacer la misma tarea. Mira estas dos: %TERMINAL_INI% $ ls | ln %TERMINAL_FIM% o entonces, usando la propia substitución de procesos: %TERMINAL_INI% $ cat -n <(ls) %TERMINAL_FIM% Un último ejemlo: tu deseas comparar =arq1= y =arq2= usando el comando =comm=, pero este comando necesita que los archivos estén clasificados. Entonces la mejor forma de proceder es: %TERMINAL_INI% $ comm <(sort arq1) <(sort arq2) %TERMINAL_FIM% Esta forma evita que tengas que hacer las siguientes operaciones: %TERMINAL_INI% $ sort arq1 > /tmp/sort1 $ sort arq2 > /tmp/sort2 $ comm /tmp/sort1 /tmp/sort2 $ rm -f /tmp/sort1 /tmp/sort2 %TERMINAL_FIM% Gente.. nuesta Convesación llegó a su fin, :( . Disfruté mucho aquí y recibí diversos elogios por los trabajos realizados a lo largo de 12 meses y, lo mejor de todo, hice muchas amistades y tomé muchos chopps gratis con los lectores que encontré por los congresos y charlas que ando haciendo por nuestro querido Brasíl. Lo que voy a escribir aquí no está arreglado ni sé si será publicado, pero como los editores de esta revista son dos locos hermosos (ambos Rafael), es posible que lo dejen pasar. Es lo siguiente: si quieren que el Papo de Botequin continue, llenen la caja postal de la _Linux Magazine_ pidiendo esto y desde ya escoja el próximo tema entre =sed + expresiones regulares= o lenguaje =awk=. De cualquier forma, en caso de que no consigamos sensibilizar la dirección de la revista, me despido de todos mandando un abrazo a los barbudos y besos a las chicas y agradezco a los mas de 100 mails que recibí (todos elogiosos) y todos debidamente respondidos. A la salud de todos nosotros: Chin, chin -Chico, cierra la cuenta que voy a cambiar de bar. 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 próxima! -- Main.DanielRefosco - 3 Jan 2007
E
dit
|
A
ttach
|
P
rint version
|
H
istory
: r14
<
r13
<
r12
<
r11
<
r10
|
B
acklinks
|
V
iew topic
|
M
ore topic actions
Topic revision: r14 - 24 Feb 2008 - 01:17:43 -
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