P1N6Ü1N0 - PERL - Introducción |
|
![]() Inicio C Perl Caml Shell GTK SQL |
En esta introducción a perl se va a suponer que se conoce algún otro lenguaje de programación estructurada, es decir, que si no conoces ninguno, y quieres aprender perl como primer lenguaje, lo mejor es que busques un libro. Perl es un lenguaje increíblemente sencillo, gran parte de su sencillez se debe a su flexibilidad, la mayoría de los lenguajes son fuertemente tipados, con un montón de restricciones, mientras que perl sólo tiene 4 tipos de datos, y las restricciones son mínimas. Su sintaxis es muy parecida a la del lenguaje C, así que para todos los que ya sepan C, aprender perl será muy fácil. Tipos de dato Perl sólo tiene 4 tipos de dato, lo que lo hace todavía más fácil. Los tipos son:
Hay un quinto tipo, los "typeglobs", pero ya no son tan usados como estos, para más información sobre ellos (en esta página hay info. sobre todos los tipos en general): man perldata En perl no es necesario declarar el tipo de las variables, de hecho, ni siquiera es necesario declararlas en absoluto, aunque se puede hacer algo parecido a una declaración si queremos limitar su campo de acción. Más adelante veremos algo más sobre esto. Escalares Las variables escalares siempre van precedidas del símbolo $. Como ya se dijo, pueden contener desde cadenas de texto hasta números de cualquier clase, por lo que es muy fácil para no liarse pensar que son siempre cadenas de texto que se pueden sumar, restar, etc. Los escalares pueden contener referencias también, esto se usa para programación orientada a objetos en PERL, pero esto se verá en otro capítulo si lo escribo algún día... Ejemplos
Listas o arrays: Las variables de tipo lista siempre tienen un símbolo @ al principio. Y contienen listas o arrays de escalares. A partir de ahora voy a referirme como listas, para no liarla. Manejo de listas: Las listas admiten las siguientes acciones:
Sobre el operador [] es importante destacar, que las listas en perl no tienen un tamaño definido, asi que se pueden añadir cuantos elementos se quiera. Y si se accede a una posición donde no se metió ningún dato, obtendremos un valor nulo. Ejemplos
Hashes Son idénticos a las listas, pero en lugar de indexarse por números, se indexan por palabras. Además, usan el símbolo % en lugar de @. Ejemplos
Los hashes tienen otra particularidad, para inicializarlos se puede utilizar esta otra notación: %hash={
nombre=> "Manolo",
edad=> 25,
peso=> "muy pesadito"};
Ficheros Son las únicas variables que no llevan mochila (no tienen un simbolito a la izquierda). Cuando abrimos un fichero en PERL, le asociamos un descriptor de fichero, este nos sirve luego para leer o escribir. Estas operaciones no necesitan llamar a ninguna función, luego veremos cómo se hace. Los descriptores de fichero suelen ponerse en mayúsculas para que destaquen bien sobre el resto de variables, y no se confundan. Lectura de fichero Es una operación realmente sencilla, veamos varios ejemplos: @lista=<FICHERO>;
$variabe=<FICHERO>;
while(<FICHERO>)
while (<STDIN>)
{
print;
}
Este ejemplo tan simple, hace lo mismo que el comando cat sin parámetros, lee líneas de la entrada estandar y las escribe por la salida estandar. No importa si no lo entiendes aun, pero vete haciendo a la idea de que existe un buffer para las lecturas de fichero, y se puede aprovechar para escribir código más cómodamente. Escritura de fichero Para escribir en un fichero, podemos usar la función print de perl, que escribe cosas por defecto en pantalla, indicando como primer parámetro el fichero, y sin coma: print FICHERO "esto es un ejemplo"; Lógica En esta parte voy a intentar explicar simplemente qué cosas son ciertas para perl y cuales falsas, y cómo usar la lógica en perl. En las secciones anteriores ya se habló varias veces de un valor nulo. Este es similar al valor NULL de C, pero se parece bastante más al valor nulo de SQL. Es simplemente la ausencia de dato. Este valor en un if siempre se evalua a falso. Y se utiliza bastante para cosas como detección de un fin de fichero. Otra cosa que evalúa a falso en un if (o while, o lo que sea) es el número 0. Los operadores lógicos son los siguientes:
Perl no evalúa todas las ramas de una expresión or, evalúa hasta que una se cumple, esto permite escribir cosas como la siguiente:
$variable=lee_valor() || error("no puedo leer el valor");
Esto simplemente llama a lee_valor, y si devuelve un nulo, como hay un or,
ejecuta la otra rama. Es una forma corta de escribir:
if (not $variable=lee_valor())
{
error("no puedo leer el valor");
}
Es evidente que la forma de arriba es bastante más cómoda. De la misma forma, si usamos el and, si alguna de las ramas se evalúa a falso, no se siguen mirando las siguientes. Control de flujo Cómo dije, se supone que ya sabeis utilizar algún otro lenguaje de programación, asi que simplemente voy a poner la sintaxis de perl para control de flujo. if (EXPR) BLOCK if (EXPR) BLOCK else BLOCK if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK LABEL while (EXPR) BLOCK LABEL while (EXPR) BLOCK continue BLOCK LABEL for (EXPR; EXPR; EXPR) BLOCK LABEL foreach VAR (LIST) BLOCK LABEL BLOCK continue BLOCK
La etiqueta es opcional, si se usa sirve para cuando poneis la sentencia next, que perl sepa a donde saltar. Pero esto es como los horribles 'goto', asi que mejor si no se usa (opinion personal, claro). De esta lista, destacan dos cosas, el for, que aunque es como el de C, puede que no sepas C. Dentro de los paréntesis hay tres expresiones, la primera es para inicializar el valor de variables, la segunda es una condicion que si cuando no se cumpla detendrá el bucle, y la última es para modificar la variable de control de bucle (si la hay). Pueden estar vacías:
for (;;) { }
Este ejemplo hace lo mismo que:
while (1) { }
...es decir, un bucle infinito. También destaca foreach, porque es algo que no existe en los principales lenguajes de programación estructurada. foreach sirve para recorrer una lista haciendo algo a cada elemento. Funciona del siguiente modo, para cada elemento de la lista 'LIST', lo mete dentro de la variable 'VAR' y ejecuta el código del bloque. Por ejemplo:
@lista=("perro", "gato", "pez", "buitre carroñero");
foreach $elemento (@lista)
{
print $elemento;
}
Este ejemplo imprime en pantalla todos los elementos de la lista. Buffers En la sección de ficheros ya se comentó algo sobre los buffers de perl, aquí se va a extender un poco más esta explicación. Hasta donde yo conozco, hay dos buffers, uno para escalares y otro para listas. El buffer de escalares se puede acceder en cualquier momento mediante $_ El buffer de listas se puede acceder en cualquier momento mediante @_ De todos modos, muchas funciones de perl, como print, son capaces de trabajar con estos buffers si no indicamos parámetros. Si ponemos print a secas, lo que se imprimirá es el contenido del buffer. Del mismo modo, si ponemos print FICHERO se escribirá el contenido del buffer de escalares en el fichero. El buffer de listas se utiliza para manejar el paso de parámetros a funciones. La función que más se utiliza sobre este buffer es shift. Al poner shift a secas, nos devuelve el primer elemento del buffer de listas, y lo elimina. Se suele usar en funciones para extraer los parámetros. Para ver las funciones que permiten trabajar con estos buffers: man perlfunc Funciones Las funciones en perl son increíblemente flexibles y fáciles de manejar. No tienen ninguna restricción, tanto podemos devolver un número, como una lista, como no devolver nada, incluso una misma función, puede devolver cosas distintas cada vez. Además, no se declara en ningún sitio los parámetros, porque son variables, como los de shell scripting, cuando alguien llama a nuestra función con una lista de parámetros, estos se colocan en el buffer de listas y nuestra función puede cogerlos como más le apetezca, aunque lo más corriente es usar shift. Las funciones se declaran de esta forma tan sencilla:
sub nombre_funcion
{
CODIGO
}
Y luego para llamar a la función, podeis hacerlo como en C o Pascal, pero perl ofrece la posibilidad de llamarla sin poner los paréntesis, aunque yo prefiero ponerlossiempre que haya al menos un parámetro, porque facilitan la lectura del código. Perl ofrece un amplio conjunto de funciones clasificadas por categorías, para verlas, solo teneis que teclear el siguiente comando: man perlfunc Declaracion de variables En perl no es necesario declarar las variables, sin embargo, es posible hacer que pertenezcan sólo a una determinada zona del programa, lo que es muy aconsejable porque evita fallos tontos difíciles de encontrar cuando un programa es un poco grande. La forma de hacer esto es: my ($variable);
my $variable=valor;
Expresiones regulares Las expresiones regulares en perl funcionan igual que en el programa sed (ver shell scripting) así que ya no repito esto. Se usan igual, pero sacando la palabra sed, claro. Ejemplo
while (<STDIN>)
{
s/a/A/g;
print;
}
Este ejemplo lee por la entrada estandar líneas, y las reescribe cambiando todas las a minúsculas por a mayúsculas. Algo que creo que no comenté en la sección de sed en Shell scripting es la posibilidad de extraer trozos de una expresion regular. Para esto basta con encerrar trozos de esta entre paréntesis, luego se pueden acceder con $ seguido de un número. Por ejemplo:
while (<STDIN>)
{
/([^ ]*) (.*)/;
print "la primera palabra de la línea es: $1 \n";
print "el resto de la línea es: $2 \n";
}
Este ejemplo separa en cada línea la primera palabra del resto y las imprime en pantalla. La forma en que funciona es sencilla, entre los primeros paréntesis dice "repeticiones de caracteres que no sean un espacio", luego fuera de los paréntesis nos comemos el espacio, y entre los segundos paréntesis pone "repeticiones de caracteres". Módulos Perl permite hacer módulos, como cualquier lenguaje que se precie. Y además, en perl es posible hacer estos módulos en C, compilarlos, y llamar a sus funciones desde un script, lo que lo hace especialmente atractivo. Por ejemplo, existen módulos para perl que le permiten usar la librería GTK, Qt, GGI, y pronto hasta GGL (entre otras). Para utilizar un módulo en perl, simplemente se pone esto: use modulo; Así de simple, y ya podemos usar todas las funciones del nuevo módulo. Además, perl ofrece un programa, llamado perldoc, que permite ver la documentación de los módulos. Muchos módulos no tienen páginas de manual precisamente pro eso, están preparados para ofrecer ayuda mediante perldoc. Cómo ejemplo, podeis probar lo siguiente: perldoc Socket Ejemplos Voy a terminar esta introducción a perl con un par de ejemplos comentados, esperando que ayuden a entender todo lo que conté antes. Voy a empezar con un ejemplo del que se habló mucho, porque resulta que hace lo mismo que formail, y cuando lo escribí no me di cuenta, pero bueno, es pequeño, asi que sirve para aprender cosas. Ejemplo 1
#!/usr/bin/perl
my(@mail);
sub procesa
{
open(FILE,">/tmp/vermail.$$");
print FILE @mail;
close(FILE);
system("cat /tmp/vermail.$$|procmail");
}
while (<STDIN>)
{
if (/^From .*/)
{
if (@mail) {procesa;}
@mail=();
}
push @mail,$_
}
if (@mail) {procesa;}
Este ejemplo lee un folder de correo, y hace que procmail procese cada mensaje. Paso a explicar cómo funciona este ejemplo: En principio, ponemos "#!/usr/bin/perl". Como ya sabréis, cuando se pone al principio de un script "#!cosa" lo que se consigue es que si le damos permisos de ejecución, al intentar ejecutarlo se ejecute realmente lo siguiente: cosa script A continuación declaramos la variable @mail de forma que tenga un nulo. Esto lo pongo por costumbre, más que nada, porque en CGI's incrementa mucho la seguridad. Luego creamos una función para procesar un mensaje de correo, que simplemente escribe el mensaje en un fichero y luego se lo manda a procmail. La parte interesante es la de abajo, donde mediante un bucle vamos leyendo de la entrada estandar, y para cada línea, miramos si empieza por la palabra From (recuerda que ^ encaja con el principio de la línea), y si es así miramos si la variable @mail no está vacía (nula), en cuyo caso mandamos a procesar el mail. Esto es necesario porque la primera vez que encontremos un from, la variable @mail no contendrá nada, asi que va a ser nula con seguridad. Además, borramos la lista. En cualquier caso, metemos la línea leida en la lista @mail. Al final del folder no hay un From, asi que para asegurarnos de que el último mail se escribe, es necesario procesarlo explícitamente. Controlamos que la lista no esté vacía para el caso en que el folder esté completamente vacío. Ejemplo 2 Vamos ahora con un ejemplo algo más útil, este programa es el que genera automáticamente las noticias que podeis ver en la página web (actualmente hay una versión más completa, pero ya es demasiado grande para ponerla aquí). Este script analiza las noticias escritas con una notación muy simple, y las convierte a HTML, para poder ser insertadas en la página. El formato de las noticias es el siguiente: **HEADER 02/07/99: Especificación XML confirmada **BODY El W3C ha confirmado la especificación de XML. Más que nada cómo meterlo en HTML y unas cosas más. Recordemos que a día de hoy sólo Microsoft Internet Explorer 5.0 soporta este estándar, aunque Netscape también lo hará con su Communicator 5.0 **BY GPUL **BLINK http://ceu.fi.udc.es/GPUL **LINK http://ceu.fi.udc.es/GPUL/articulos/W3C_ratifies_XML_spec.txt BLINK es el enlace al origen de la noticia. Y aquí teneis el código que analiza esto para crear las noticias:
#!/usr/bin/perl
my $BY="";
my $mode=0;
while (<>){
if (/\*\*HEADER/)
{
if ($mode ne 0) { die "Error de sintaxis"; }
$mode=1;
print "<TABLE CELLPADDING=4 CELLSPACING=0 BORDER=0 \
BGCOLOR=\"FFFF99\">\n";
print "<TR>\n";
print " <TD BACKGROUND=\"images/bordesi.gif\" \
WIDTH=\"16\" BGCOLOR=\"FFFFFF\"> </TD>\n";
print " <TD BGCOLOR=\"FF0000\" WIDTH=\"100%\">\n";
print " <FONT COLOR=\"FFFFFF\" FACE=\"Helvetica\">\n";
}
elsif (/\*\*BODY/)
{
if ($mode ne 1) { die "Error de sintaxis"; }
$mode=2;
print " </FONT>\n";
print " </TD>\n";
print " <TD BACKGROUND=\"images/bordesd.gif\" \
WIDTH=\"16\" BGCOLOR=\"FFFFFF\"> </TD>\n";
print "</TR>\n";
print "<TR>\n";
print " <TD> </TD>\n";
print " <TD>\n";
}
elsif (/\*\*BLINK/)
{
if ($mode ne 3) { die "Error de sintaxis"; }
$mode=4;
print "<A HREF=\"";
}
elsif (/\*\*BY/)
{
if ($mode ne 2) { die "Error de sintaxis"; }
$mode=3;
print " </TD>\n";
print " <TD> </TD>\n";
print "</TR>\n";
print "<TR>\n";
print " <TD> </TD>\n";
print " <TD ALIGN=RIGHT>\n";
print " <TABLE WIDTH=\"100%\"><TR><TD \
ALIGN=LEFT>\n";
print " Origen: ";
}
elsif (/\*\*LINK/)
{
if ($mode lt 3) { die "Error de sintaxis"; }
if ($mode eq 4) { print "\">"; }
print $BY;
$mode=5;
print "</A></TD>\n";
print " <TD ALIGN=RIGHT><A HREF=\"";
}
else
{
if ($mode eq 0) {die "ERROR DE SINTAXIS";}
if (not /^\ *\n/)
{
s/\n//;
# Cambiamos las tildes y demás cosas
s/&/&/g;
s/á/á/g;
s/é/é/g;
s/í/í/g;
s/ó/ó/g;
s/ú/ú/g;
s/ü/ü/g;
s/Á/Á/g;
s/É/É/g;
s/Í/Í/g;
s/Ó/Ó/g;
s/Ú/Ú/g;
s/Ü/Ü/g;
if ($mode eq 1)
{
print " <B>";
print;
print "</B>\n";
}
elsif ($mode eq 3)
{
$BY=$_;
}else{
print "$_\n";
}
}
}
}
print "\"><IMG SRC=\"images/mas.gif\" BORDER=0 \
ALT=\"- MÁS -\"></A></TD>\n";
print " </TR>\n";
print " </TABLE>\n";
print " </TD>\n";
print " <TD> </TD>\n";
print "</TR>\n";
print "</TABLE>\n";
print "<BR>\n";
La explicación punto por punto sería muy tediosa, además, creo que despues de la introducción y el ejemplo anterior, podeis entender este ejemplo perfectamente. Realmente, la mayoría son print's, asi que no tiene mucha ciencia. La única novedad es eso de die. Es una función que al llamarla con un string, lo pone cómo si fuera un error del compilador y termina la ejecución. Es lo que se suele usar para terminar con error. Ahora mismo ando pensando una alternativa que me permita manejar a la vez las noticias de GGL y las de mi página personal, creando un formato para escribir una plantilla, en la que se escribe tal cual una noticia de GGL/P1n6ü1n0, pero poniendo en cada campo un valor que entienda el script. De esta forma, al script le dices la noticia que debe procesar, y la plantilla que debe usar, y ya te genera la noticia para una u otra página simplemente rellenando en la plantilla. El generador de páginas de GGL, que está bastante más avanzado: permite sacar la fecha en formato inglés/español, usa un formato de entrada más amigable, permite poner links por el medio del mensaje... podeis bajároslo pinchando aquí. Y podeis bajaros un ejemplo de cómo se escriben las noticias en él aquí. |
| Los gráficos de esta página han sido creados con GIMP. |