August 2007 Archives

Redirecciones

| | Comments () | TrackBacks (0)

La Columna.pl #3

Redirecciones

Bueno, el ofrecer disculpas por tardanzas tan prolongadas en la entrega de esta columna, ya se está haciendo costumbre, ¡y apenas van tres columnas! Por ahora mejor tomaré otro approach para las próximas liberaciones de la misma: Se harán nuevas entregas cuando estén listas. Un enfoque plenamente debianero. Como sea, durante el mes pasado estuve principalmente preparándome, asistiendo y recuperándome de la Debian Conference que se llevó a cabo en las tierras del whisky, Escocia (pueden ver fotografías en mi galería). Como éste era un viaje que había planeado con mucha antelación, cuando supe que el YAPC::NA se realizaría en Houston, no pude dejar de lamentarme semanas y semanas por que estaría destinado a no asistir. En fin, a ver qué tal el próximo año. Gracias a las personas que preguntaron sobre el paradero de ésta, su columna de confianza. En fin. En los últimos días estuve revisando un sitio que implementaba cosas interesantes. Entre ellas, una aplicación que hacía redirecciones en web. Éstas son algo populares, pero no muy conocidos: Una aplicacioncita web que nos permite crear URLs del tipo: http://www.midominio.com/cgi-bin/forward.cgi?url=damog.net. Básicamente, es un CGI que recibe un argumento y hace una redirección hacia ese sitio, ¿muy simple? Quizás sí, pero nosotros podemos agregarle mucha más funcionalidad muy interesante. Es cierto que dichas redirecciones pueden hacerse con mod_rewrite de Apache o similares, pero obviamente no le podemos agregar tanta flexibilidad y triques como con un script en Perl. Lo que quiero, entonces, es un redireccionador que en primer lugar, verifique que la URL sea válida, quizá escribir en un log o una base de datos y haga la redirección. Además, utilizaremos un poco de rewrites para añadirle un poco de atractivo visual al asunto. Empezaré a escribir el redir.cgi:

 #!/usr/bin/perl

 use strict;
 use warnings;

 use CGI qw(:standard);
 use Data::Validate::URI qw(is_http_uri is_https_uri);

 my $url = param('url') || 'http://www.damog.net/‘;
 $url =~ s/^http(s?)://http$1:///;

 &wrong($url) unless is_http_uri($url) || is_https_uri($url);

 # Más código…
 # Quizás escribir a un log, etc..
 print “Location: $url”, “\n\n”;

 sub wrong {
        my ($url) = shift;
        print “Content-Type: text/plain”, “\n\n”;
        print “It looks like $url is not a valid URL!”;
        exit;
 }

Es un código bastante corto y simple. Usamos un par de pragmas, un par de módulos, procesamos el parámetro que recibiremos, validamos y redireccionamos. Vamos por partes. Para poder realizar este ejemplo, necesitaremos tener habilitada la ejecución de CGIs en nuestro servidor web. Para más información al respecto, puedes revisar la información de Apache o Cherokee al respecto, la explicación de tal procedimiento está fuera de contexto en esta columna. Encuentra enlaces útiles más abajo, en la sección de Referencias útiles.

 #!/usr/bin/perl

 use strict;
 use warnings;

Desde luego, nuestro CGI necesitará saber dónde encontrar el intérprete para la ejecución. Además, como buena práctica de programación, añadiremos los pragmas strict y warnings. Desde un personal punto de vista, una vez que nuestra aplicación en desarrollo haya quedado limpia de errores fatales o advertencias, podríamos deshabilitar ambos pragmas, los cuales podrían volverse a cargar cuando se haga debugging o algo similar; pero a final de cuentas es sólo un punto de vista personal que cada quién seguirá teniendo sus propias razones y necesidades.

 use CGI qw(:standard);
 use Data::Validate::URI qw (is_http_uri is_https_uri);

Utilizamos dos módulos. El primero es un módulo que pertenece a Perl y que nos permite un manejo muy sencillo de, claro, CGIs y todo alrededor de ellos. Nosotros realmente lo utilizamos para obtener el parámetro que se le mande al script, con la función param(), que de hecho puede recibir los parámetros tanto en HTTP GET o POST. También podríamos obtener dicho parámetro desde el hash %ENV, pero hay que hacer un poco más de talacha, así que mejor usaremos CGI.pm y listo. Data::Validate::URI es un módulo que encontré en CPAN que hace mínimamente lo que necesitamos, validar URIs. Si una cadena es una URI de HTTP o HTTPS, se valida y regresará falso en dado que no lo sea. Eso es más que suficiente. La explicación sobre la instalación de módulos de CPAN queda fuera del contexto de esta columna.

 my $url = param('url') || 'http://www.damog.net/‘;
 $url =~ s/^http(s?):/{1,2}/http$1:///g;

Creamos la variable $url con el parámetro GET o POST que nos traen al CGI. En caso de que no exista dicho valor, colocaremos alguna otra cadena, en mi caso, mi sitio. La siguiente línea tiene un poco de truco. Resulta que me idea era procesar este script pasándolo por una regla de Rewrite de Apache. Sin embargo, cuando mod_rewrite recibe en la URL la cadena ‘http://’, la cambia, por seguridad y motivos similares, a ‘http:/’, entonces cuando estaba haciendo pruebas con este redireccionamiento, el script fallaba pues intentaba entrar a digamos, ‘http:/google.com’; entonces la segunda línea es un hack para este comportamiento. ¿Pero qué hace la expresión regular? Bueno, hace un search and replace, en la cadena busca aquello que empieza con ‘http’, después puede contener o no (es decir, cero o una vez) la ’s’ -y ésto a su vez lo cachamos con un paréntesis-, seguido de dos puntos y una diagonal, que puede estar una o dos veces. Todo eso lo cambiamos por ‘http’, el valor que cachamos en el paréntesis, $1, dos puntos y dos diagonales. Lo hacemos las veces que sea necesario implementando el modificador ‘g’. Entonces, si recibimos ‘https:/google.com’ lo cambiará a ‘https://google.com’; y si recibimos ‘http://www.damog.net’, lo cambiará a, exactamente lo mismo, ‘http://www.damog.net’.

 &wrong($url) unless is_http_uri($url) || is_https_uri($url);

Llamamos a la subrutina wrong(), pasándole la URL, a menos que sea una URI de HTTP o de HTTPS válida. is_http_uri e is_https_uri nos devolverán indefinido, en caso de que falle la validación y lanzarán wrong, que lo único que hace realmente es imprimir un error en el browser. Veremos la subrutina unas cuantas líneas abajo. Antes pudimos haber guardado en base de datos, utilizar la variable $ENV{REMOTE_ADDR} o muchas cosas, usted decida.

 print "Location: $url", "\n\n";

Éste es un header que tenemos que colocar en la respuesta del cliente, para que el servidor tome la nueva URL y se haga una redirección. El usuario siempre debe recordar que los headers son colocados hasta cuando se encuentren dos nuevas líneas. De otra forma, nuestro servidor web local no definirá dónde acaban las cabeceras y no terminará la ejecución con error. Hasta este punto pasamos las validaciones y le aplicamos el hack para corregir el inconveniente con mod_rewrite. Desde luego que verificar si la URL es válida, es decir, que la URL nos lleve realmente a algún lado o página con contenido válido o que el servidor remoto esté efectivamente funcionando, está fuera del contexto de esta columna, nosotros simplemente cuando nos llega la petición tomamos la URL y colocamos un encabezado en nuestra respuesta en la comunicación HTTP. ¿Lindo, no? :-) Puedes usar algunos otros métodos para validar si la URL remota realmente es válida, quizás usando Net::Ping. Ahora, veamos la subrutina wrong.

 sub wrong {
        my ($url) = shift;
        print "Content-Type: text/plain", "\n\n";
        print "It looks like $url is not a valid URL!";
        exit;
 }

Tomamos la variable $url con la URL que le pasamos. shift saca el primer elemento de un arreglo, en este caso @_. Y listo, imprimimos un mensaje en pantalla. Hay que colocar una cabecera Content-Type, dejar doble línea y ponemos el mensaje. Luego buscamos la puerta de salida y terminamos. Hasta ahora es bastante simple y bien programado. Podemos probar la funcionalidad yendo hacia: http://www.damog.net/cgi-bin/redir.cgi?url=http://www.google.com o cualquier otra URL, inténtelo. Incluso podríamos poner una formita web, pues param() puede tomar, como ya lo decía argumentos POST o GET, indistintamente. Como quiero empezar a usar este método para hacer ligas desde mi sitio a otros y quiero que tenga una mejor apariencia que esa URL larga y fea, hago uso de mod_rewrite y coloco un .htaccess en mi servidor web:

 <IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteRule ^->(.*)$ /cgi-bin/redir.cgi?url=$1 [L]
 </IfModule>

Con dicha regla lo que hago es que cuando reciba una URL con una flechita (`->’), tomaré lo que venga a continuación y lo consideraré una URL, que es lo que le pasaré al redir.cgi. Entonces, puedo llamar http://www.damog.net/->http://www.google.com y hará lo que quiero que haga, la ejecución del CGI con la URL como parámetro, y con la flechita se ve muy intuitivo. ¿Qué tal implementar además, logs o escritura en base de datos, o algo así? Inténtalo, la imaginación es el límite. Me gustaría mucho leer sus comentarios.

Referencias útiles

Autor

Durante el día, David Moreno Garza (http://www.damog.net/) desarrolla aplicaciones, sistemas y proyectos para una incipiente empresa internacional de telecomunicaciones; adicionalmente es consultor independiente en empresas mexicanas y extranjeras utilizando Perl. Durante la noche intenta salvar al mundo del mal usando expresiones regulares y netiquette.

Licencia de uso

Copyright © 2007 David Moreno Garza. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/).


Sobre La Columna.pl

La Columna.pl

es una columna quincenal que escribe el autor alrededor de Perl. Está inspirado en las columnas que Randal L. Schwartz ha escrito desde hace varios años ya. Por medio de recetas, consejos, instructivos y guías, el autor pretende propiciar interés en la gente para que conozca un poco más a fondo este apasionante lenguaje de programación y así fomentar una comunidad más sólida alrededor de él. Visite http://www.damog.net/columnapl.

Manejo del tiempo con Perl

| | Comments () | TrackBacks (0)

Manejo del tiempo con Perl

La Columna.pl #1 - Mayo 21, 2007. Recientemente, por algunas de las necesidades que tuvimos en el trabajo, necesitamos manejar de alguna forma fechas y horas desde nuestros scripts y aplicaciones en Perl. Hace no-sé-cuántos años, los franceses propusieron un sistema decimal para manejar el tiempo, pero el método fue impopular entre la comunidad científica. Si hubiera sido así, manejar las fechas y horas en cualquier sistema, hubiera sido tan fácil que no habría tantas implementaciones para trabajar con él, como hoy en día. Pero bueno, el hubiera no existe. En Perl a veces nos confunde sobre si necesitamos usar localtime, time, gmtime, DateTime.pm, etc. para trabajar con el tiempo. En realidad es mucho más sencillo de lo que parece. Espero que estas minirecetas le sirvan a alguien cuando encuentre este texto buscando por ahí en la red el manejo del tiempo con Perl. Lo haré a manera de FAQ. ¿Cómo obtengo la fecha actual? La función localtime nos devuelve la fecha actual, pero lo hace en forma de una lista de 9 elementos que podemos obtener de una manera sencilla: my @fecha = localtime; # La lista tiene el formato (seg, min, hora, día mes, mes, año, día sem, día año, DST). De esta forma, cada uno de los elementos del arreglo @fecha, será, por orden, el de ese formato, de ahí podrías usar $fecha[0] para obtener el segundo, $fecha[1] para los minutos, y así sucesivamente. Puedes obtener más información en perldoc -f localtime. ¿Y time? ¿Qué es? ¿Cuándo lo utilizo? ¿localtime no se mandaba llamar como localtime(time)? La función time nos regresa la cantidad de segundos desde el epoch, léase, el 1 de enero de 1970, UTC, como en la mayoría de los sistemas actuales. time realmente lo hace desde cualquier epoch de acuerdo a la arquitectura de la máquina, pero supondremos que ese no es el caso. damog@cochina:~$ perl -e ‘print time.”\n”;’ 1179168385 localtime toma como parámetro una cierta cantidad de segundos. Por default, toma el valor de time. Así que podemos usar tanto localtime como localtime(time) cuando usemos dicha función. Pero lo que yo quiero es obtener la fecha en el formato que yo quiera. Tienes dos opciones. Una, es usar el contexto escalar de localtime, es decir, tratar lo que nos regresa localtime como una variable escalar, no como una lista. Ejemplo: damog@cochina:~$ perl -e ‘$fecha = localtime; print $fecha, “\n”;’ Wed May 16 19:29:55 2007 damog@cochina:~$ Sencillo, ¿no? Lo cual es lo mismo que usar la función scalar, sin tener que asignar forzosamente a una variable escalar: damog@cochina:~$ perl -e ‘print scalar localtime, “\n”‘ Wed May 16 19:30:55 2007 damog@cochina:~$ Puedes echar un ojo a perllocale si es que la fecha te interesa en otro idioma. Lo más sencillo, desde mi muy personal punto de vista, y la otra opción, es usar strftime. No hay que temer a usarlo, básicamente utiliza la misma sintaxis que su predecesor, strftime de C. A final de cuentas es bien sencillo (incluso a veces yo echo un rápido vistazo a la página de strftime de PHP que explica cómo usar la función y es la misma implementación). Esta función se encuentra en el módulo estándar POSIX, que podría ser que ya tengas cargado en tu distribución o sistema operativo. Lo que strftime necesita, es el formato en el que necesitas la fecha, y el tiempo en segundos desde el epoch. Supongamos que queremos la fecha del día de hoy, en el formato AAAA-MM-DD: damog@cochina:~$ perl -e ‘ > use POSIX qw(strftime); > print strftime(”%Y-%m-%d”, localtime), “\n”; > ‘ 2007-05-17 damog@cochina:~$ ¿Muy simple, no? Incluso, si queremos hacer un poco de matemáticas con días, lo podemos hacer con strftime, por ejemplo, queremos la fecha de ayer en formato AAAA-MM-DD hh-mm-ss: damog@cochina:~$ perl -e ‘ > use POSIX qw(strftime); > print strftime(”%Y-%m-%d %H:%M:%S”, localtime(time - 86400)), “\n”; > ‘ 2007-05-16 10:14:06 damog@cochina:~$ Como que no entendí muy bien eso de los contextos de localtime. ¿Me lo podrías aclarar? Claro. localtime es manejado por Perl desde dos conceptos para su valor de retorno. Uno es el contexto de escalar y uno en el contexto de lista (como sabes, Perl utiliza estos dos tipos -u otros- de conceptos para el manejo de sus variables). El contexto escalar de localtime es el que nos regresa una fecha formateada (puedes echar un ojo también a la función scalar, si tienes duda al respecto); el contexto de lista de localtime nos regresa un arreglo, donde cada uno de sus elementos, corresponde a un atributo de la fecha, como la documentación de la función nos lo indica y como lo indicaba líneas arriba. Es bien simple. De hecho, los conceptos de escalar y lista es muy simple. Una variable escalar puede contener cadenas, valores numéricos, referencias, etc. Una variable de lista son arreglos, los cuales, a su vez, contienen elementos escalares, listados en ellos. Como una nota al margen, actualmente las variables escalares de las listas son manejadas de la forma $arreglo[2], por ejemplo, así es como Perl 5 lo maneja. En Perl 6 se utilizarán los elementos de las listas de la forma @arreglo[2], lo cual es mucho más intuitivo y natural, pero mientras Perl 6 no vea la luz oficialmente, esta nota queda sólo como una acotación adicional :-) Aún se me hace un poco complicado, ¿no hay una forma más fácil? ¡Desde luego! There is more than one way to do it. Hay una cantidad enorme de módulos de fecha y hora disponibles en CPAN, sin embargo, el que ha gozado de gran aceptación por su buena implementación y diseño, es DateTime. Con DateTime podemos manejar fechas y tiempos en una forma mucho más natural e intuitiva, podemos hacer operaciones matemáticas de una forma mucho más lingüística, que puede terminar ayudando mucho más la naturaleza y la lógica de nuestros programas: ¿Cómo puedo obtener la hora actual con DateTime? Bien simple: damog@cochina:~$ perl -e ‘ > use DateTime; > > my $hoy = DateTime->now(); > print $hoy, “\n”; > ‘ 2007-05-17T16:26:12 damog@cochina:~$ Sin embargo, hay que ser un poco cuidadosos al usar el método now() pues nos regresa la fecha en UTC. Para eso, podemos crear el objeto $hoy, especificando nuestra zona horaria: damog@cochina:~$ perl -e ‘ > use DateTime; > my $hoy = DateTime->now(time_zone => “America/Chicago”); > print $hoy, “\n”; > ‘ 2007-05-17T11:29:51 damog@cochina:~$ Ese objeto, puede ser utilizado para muchas más cosas. Por ejemplo, a una fecha, sumarle un mes, no es lo mismo que sumarle 28 días, ó 30, ó 31. Mira este ejemplo, donde crearemos un objeto DateTime con una fecha en el pasado y le sumaremos un mes y luego le restaremos dos años: damog@cochina:~$ perl -e ‘ > use DateTime; > my $fecha = DateTime->new( > year => 1984, > month => 8, > day => 8, > hour => 2, > minute => 0); > print $fecha->add(months => 1), “\n”; > print $fecha->add(years => -2), “\n”; > print “DateTime es la onda!\n”; > ‘ 1984-09-08T02:00:00 1982-09-08T02:00:00 DateTime es la onda! damog@cochina:~$ Podemos ver que creamos un objecto DateTime llamado $fecha que apunta hacia el 8 de agosto de 1984, 2 de la mañana. A él, le sumamos un mes y luego le restamos dos años. Simple, ¿no crees? ¿Y cómo puedo hacer una diferencia de fechas? Creo que lo más sencillo para utilizar, es Date::Manip. Observa este ejemplo: damog@cochina:~$ perl -e ‘ > use Date::Manip; > my $hoy = ParseDate(”today”); > my $fecha_nacimiento = ParseDate(”1984-08-08 02:00:00″); > $delta = DateCalc($fecha_nacimiento, $hoy, \$err, 1); > print $delta, “\n”; > ‘ +22:9:1:2:9:55:34 damog@cochina:~$ Básicamente, creamos dos cadenas, $hoy y $fecha_nacimiento y luego las pasamos por &DateCalc, que requiere ambas fechas, una referencia a una variable de error y la variable 1, como modo de operación que nos hará la diferencia entre ambas fechas. Esto nos regresa una cadena parseable para el método &ParseDateDelta, cuyo formato nosotros podemos utilizar y parsear: my ($anos, $meses, $semanas, $dias, $horas, $minutos, $segundos) = $delta =~ /^\+(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)$/; Echando rápidamente una mirada a la cadena, podemos saber que en el momento de escribir esta guía, tengo 22 años, 9 meses, 1 semana, 2 días, 9 horas, 55 minutos y 34 segundos de vida. :-) ¿Pero y si quiero convertir una cierta fecha a segundos desde el epoch? El módulo POSIX también proporciona una función bien sencilla llamada mktime que puede ser usada para precisamente esto. Como puede verse en la documentación de esta función, la sintaxis es la siguiente: mktime(sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0); Quiero saber la cantidad de segundos hasta el momento que mis padres me han dicho que nací, 2 am, del 8 de agosto de 1984. El valor mon es contabilizado desde 0, el cual es enero, y así sucesivamente hasta el 11 que es diciembre. De forma similar con wday y yday. El argumento year, empieza desde 1900. Dicho lo anterior, podemos calcular: damog@cochina:~$ perl -e ‘ > use POSIX qw(mktime); > > print mktime(0, 0, 2, 8, 7, 84), “\n”; > ‘ 460800000 damog@cochina:~$ Ahí utilizamos 0 para el segundo, 0 para el minuto, 2 para la hora, 8 para el día del mes, 7 para el mes del año (agosto, recordemos que empiezan desde cero) y 84 para el año desde 1900. Nací en el segundo 460800000 desde el epoch. Pero vamos a ver si eso es cierto, usaremos una combinación de mktime y localtime, en su contexto escalar: damog@cochina:~$ perl -e ‘ > use POSIX qw (mktime); > > print scalar localtime(mktime(0, 0, 2, 8, 7, 84)), “\n”; > ‘ Wed Aug 8 02:00:00 1984 damog@cochina:~$ Parece que así es :-) Nací en el segundo 460800000. Era miércoles :-) Como puedes ver, no es la gran cosa procesar fechas y horas en Perl, realmente es sencillo y sólo es cosa de excarvarle un poquito por aquí y por allá y usar cinta adhesiva para obtener lo que queremos de una forma eficiente y útil. Ojalá te sirva, espero que te hayas divertido aprendiendo un poquito sobre el tiempo en Perl así como yo me divertí escribiendo. Puedes hacerme llegar tus comentarios a <damog@ciencias.unam.mx>. Información extendida recomendada:


Sobre el autor: Durante el día, David Moreno Garza (damog) desarrolla aplicaciones, sistemas y proyectos para una incipiente empresa internacional de telecomunicaciones; adicionalmente es consultor independiente en empresas mexicanas y extranjeras utilizando Perl. Durante la noche intenta salvar al mundo del mal usando expresiones regulares y netiquette.


Copyright © 2007 David Moreno Garza.This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/).

Pequeñas herramientas para grandes necesidades


La Columna.pl #2

Pequeñas herramientas para grandes necesidades

Se han pasado muy rápidamente estos últimos 15 días. Entre algunas pláticas, trabajo y otras cosas, pareciera que el tiempo simplemente se esfuma tan, tan rápidamente. Como sea, ya estamos en la segunda entrega de La Columna.pl. En esta quincena quiero tocar un tema bien interesante que son esas pequeñas herramientas que nos pueden llenar de una manera muy especial alguna de nuestras necesidades. ¿Hay algo por ahí que quieras automatizar pero no te decides? Inténtalo. El ejemplo que voy a poner aquí es acerca de una pequeña utilidad que hice para revisar el estado de la batería de mi laptop. Como es bien sabido por algunos de ustedes, amables lectores, utilizo una máquina PowerBook G4, sobre Debian GNU/Linux: En esta máquina hago la mayoría de mi trabajo, que se basa principalmente en desarrollo de software y algo de administración de sistemas. La mayoría de mi trabajo lo hago en esta máquina que es casi tan estable como una piedra. En fin, las computadoras Apple, como ésta, utilizan un microcontrolador que gestiona las funcionalidades de energía, tales como el control de suspensión, el nivel de batería y otras similares, llamado PMU. Lamentablemente las aplicaciones actualmente existentes que monitorean los atributos de PMU, en Linux sobre estas computadoras no me satisfacen del todo: Algunas son unas aplicaciones en GTK verdaderamente estorbosas; otras están integradas al panel de control de GNOME o KDE, del cual no utilizo ninguno. Opté por utilizar el control de batería de GKrellM, que es algo modesto, pero que de todas formas a veces no quería tener siempre en mi escritorio - que para empezar, no es que tenga un escritorio como tal, pues de un escritorio sólo utilizo algunos escritorios virtuales y algo de soporte de systray. Finalmente no estaba muy seguro de lo que necesitaba. Lo único seguro era mi inseguridad en el caso :-) ¡Una pequeña aplicación en Perl! Claro, desde un emulador de terminal podría llamar esta aplicación y me diría qué porcentaje tengo de batería restante en mi máquina, sería lo más simple, sencillo y a mi gusto, sería perfecto. Pues vamos a poner las manos a la obra. En mi máquina, la información de la batería se encuentra en /proc/pmu/battery_0, que luce así:

 flags      : 00000011 charge     : 3535

max_charge : 3537

current    : 0

voltage    : 12495

time rem.  : 0

El archivo indica diferentes valores para amperaje y voltaje. Los que me interesan son los valores de charge y max_charge que indican miliampers/hora de la carga actual que tiene la pila y la máxima. Lo que hay que hacer es bastante simple. Obtener el valor de charge, el de max_charge y obtener un porcentaje del primero con respecto al segundo. En esta columna tocaré algunos temas básicos pero que pueden ser de utilidad para entender algunos conceptos más adelante en otras columnas.

 #!/usr/bin/perl use warnings;

use strict;

Mando llamar al intérprete de Perl que en la mayoría de las distribuciones con binarios precompilados irá a dar a /usr/bin/perl e inmediatamente mando llamar dos pragmas de Perl: El primero, warnings, para controlar advertencias y el segundo, strict, para restringir construcciones inseguras. Es bueno siempre llamar ambos pragmas para educarnos un poco al programar. Un pragma es únicamente un indicador para el momento de la compilación, podremos estudiar un poco los pragmas en futuras columnas.

 my $pmufile = '/proc/pmu/battery_0';

Declaro la variable $pmufile que indicará la ruta absoluta del archivo que mencionaba anteriormente.

 my $filecont; {

local $/ = undef;

open(PMU, $pmufile) or die $!;

$filecont = <PMU>;

}

Aunque el uso de local ya no se aconseja mucho, es bueno a veces para utilizarlo en bloques específicos donde sólo tengamos que modificar, quizás, una variable especial, como en este caso, la variable especial $/. Esta variable nos sirve para definir el input record separator, que por default, es una línea nueva. Modificarlo nos permite hacer cosas interesantes, sobre todo cuando efectuamos un ciclo while() hacia un filehandle. En este caso, indefinimos su valor, por lo cual, luego de abrir el archivo $filename a lectura, vaciamos todo el contenido del archivo en una sola variable, $filecont, que habíamos declarado antes del bloque. En alguna columna futura tengo pensado tratar a fondo las variables especiales, que son algo muy interesante dentro de Perl.

 my($charge) = $filecont =~ /charges+:s(d+)/; my($max_charge) = $filecont =~ /max_charges+:s(d+)/;

Aquí creamos las variables $charge y $max_charge y les asignamos el valor que nos arroja nuestra expresión regular como la variable especial $1, en ambas líneas.

 my $porc = int (($charge/$max_charge) * 100);

Dividimos $charge entre $max_charge y multiplicamos el resultado por cien, para obtener el porcentaje. Sin embargo, este resultado nos arrojaría más de diez decimales, después del punto. Por ello, utilizamos la función de Perl, int, que nos regresa el valor entero de su parámetro (mi incipiente naturaleza matemática me hace hacer notar que un número entero no es necesariamente un número natural :-)).

 print "t", "Restante: $porc %", "n";
print

en realidad requiere una lista como argumento, lo que generalmente hacemos en enviarle un sólo parámetro (por ejemplo, print "Hola mundo";), sin embargo, para una notación mucho más intuitiva, ponemos el salto de línea y el tabulador como primer y tercer parámetro, una lista, precisamente. ¡Y listo! Le agrego un bit de ejecución al script, lo renombro a pila, lo pongo en /usr/local/bin o algo similar y puedo correrlo fácilmente:

 damog@cochina:~$ pila         Restante: 86 %

damog@cochina:~$

Ya luego podría usar ese comando para hacer otras cosas: parsear el valor y podría enviarme un correo avisándome que ya se me va a acabar la pila, o mandar un mensaje al systray o quizás conectarme al IRC y avisarle a mi nick al respecto; hay muchas cosas más que Perl nos facilita hacer, ¡tu imaginación es el límite! De otras muchas formas habríamos podido abrir el archivo y leer el contenido de charge y max_charge. ¿Tú de qué forma lo hubieras hecho? ¿Quizás ciclar el filehandle hasta toparse con /^max_charge/? ¿Quizás usar alguna combinación con ejecución externa de cat o de grep? Te invito a que me envíes tus comentarios. Nos leemos dentro de quince días.

Referencias útiles

Autor

Durante el día, David Moreno Garza (http://www.damog.net/) desarrolla aplicaciones, sistemas y proyectos para una incipiente empresa internacional de telecomunicaciones; adicionalmente es consultor independiente en empresas mexicanas y extranjeras utilizando Perl. Durante la noche intenta salvar al mundo del mal usando expresiones regulares y netiquette.

Licencia de uso

Copyright © 2007 David Moreno Garza. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/).


Sobre La Columna.pl

La Columna.pl

es una columna quincenal que escribe el autor alrededor de Perl. Está inspirado en las columnas que Randal L. Schwartz ha escrito desde hace varios años ya. Por medio de recetas, consejos, instructivos y guías, el autor pretende propiciar interés en la gente para que conozca un poco más a fondo este apasionante lenguaje de programación y así fomentar una comunidad más sólida alrededor de él. Visite http://www.damog.net/columnapl.

La Columna.pl

| | Comments () | TrackBacks (0)

La Columna.pl es una columna periódica en español sobre el lenguaje de programación y la cultura Perl.

Sapo verde soy yo

| | Comments () | TrackBacks (0)

I’m 23 years old since 2 am on this August, 8th.

Thanks for the congratulations messages I’ve received so far :-), resiak even sang happy birthday to me on IRC! Next year (August, 8th, 2008), 08-08-08, I will turn 24! 08+08+08! Something really bad is going to happen because of that :-) Probably that’s gonna be my really lucky year. But how en Earth can I be more lucky than what I am today? :-P In the meantime, I’ve invited my closest local friends to a bar this Friday to celebrate my birthday. Let the rum and tequila flow, baby! Yeah!

An end has a start

| | Comments () | TrackBacks (0)

July 31st was my last day working for Sixbell-Nekotec Solutions (formerly known as Nekotec Tecnología). I lasted there three years. It seems like a life was spent there, heh: I entered after turning 20 and I’m leaving some days before I turn 23.

Our future is still a bit fuzzy, but we are working on it. In the meantime, I’m getting back full-time to Mathematics next 13rd. But if our plans succeed and if everything goes right, we’ll be moving by the end of August or early September. Heh, yes, leaving school temporarily, again!

Anyway, I’m unemployed right now. Listening to music most part of the day, taking Raquel to work, coding a bit here, there, doing some Debian labor, etc.

Meh.

An End Has A Start is one of the albums by the English band, The Editors, it makes a great title for my post now :-). I just listened to Taraf de Haïdouks’ Maskarada, it’s not that great as the masterpiece as The Continuing Adventures. I’m getting addicted to the Cold War Kids.