Esta charla fue dada en la CaFeConf del año 2005. La idea era dar una aproximación a la programación con Perl.
El shebang es la primera línea que se pone en los scirpts, por ejemplo:
#!/usr/bin/ksh
O también:
#!/bin/bash
Para Perl la línea tiene que ser:
#!/usr/bin/perl
También se le pueden agregar algunos modificadores:
#!/usr/bin/perl -w
Este hace que Perl muestra advertencias sobre lo que considera dudoso. También se puede poner:
#!/usr/bin/perl -wt
Esto aparte de las advertencias, da ciertas advertencias de seguridad (código sucio).
#!/usr/bin/perl -spi.bak
Esto es bastante útil, y es una forma bastante simple de hacer un parser. Se crea un script que tenga esto como shebang, y luego se pasa un archivo como parámetro, y el script leerá línea por línea del script, y hará lo que esté indicado dentro del programa, y lo escribirá en el mismo archivo. Pero generará una copia de seguridad (el modificador "i") que terinará con .bak. El "s" permite que el script que hagamos pueda recibir de forma "rudimentaria" varios modificadores, que son eliminados del @ARGV y lo deja como una variable dentro del script. El "p" lee el STDIN y lo evalua línea por línea, cuando termina el STDIN (una señal EOF es recibida), el código termina.
Estas y otras opciones más están documentadas en la sección perlrun del manual on-line de Perl.
Las primeras líneas de siempre:
#!/usr/bin/perl -w
print "Hola Mundo!\n";
Haciendo operaciones matemáticas desde la línea de comandos:
$ perl -eprint 22 ** 1 + 11;
Esto lo que hace es elevar a la potencia 1 el 22 y sumarle 11.
En Perl pueden haber comentarios:
#!/usr/bin/perl -w
# inicio mi variable
my $var = 0;
print "Var es: '" . $var . "'\n";
Para poner comentarios solamente el #, y hasta el final de la línea. También se puede hacer otra cosa, y es ponerlo compo parte de la documentación POD del script que hagamos.
#!/usr/bin/perl -w
my $var = 0;
=head1 Comentario
my $var = 55;>
print "Var es: '" . $var . "\n\n";
print - x 50 . "\n";
=cut
print "Var es '$var'\n";
__END__
Aunque si usamos realmente la documentación en formato POD, veremos algo como:
POD_MANCHADO(1) User Contributed Perl Documentation POD_MANCHADO(1)
Comentario
my $var = 55; print "Var es: '" . $var . "\n\n"; print - x 50 . "\n";
perl v5.8.7 2005-10-11 POD_MANCHADO(1)
Perl utiliza el concepto de línea real y línea lógica, es decir, si aparece algo como:
"Hola Mundo"
;
No es un error ni nada, simplemente es una línea lógica que fue escrita en más de una línea real. También se puede hacer lo contrario:
my $b = "Hola Mundo"; print $b;
Esto guarda el "Hola Mundo" en la variable $b, y luego la imprimer por pantalla.
Todas las variables se expresan como:
$variable = "valor";
También se pueden utilizar arrays:
@arr = ("hola",
"mundo");
También se pueden emplear funciones simples de ordenamiento:
#!/usr/bin/perl -w
my @dias = ("Lunes","Martes","Miercoles","Jueves","Viernes");
my @b = sort @dias;
my @c = reverse @dias;
print "B\n";
foreach my $tmp1 (@b) { print "#->" . $tmp1 . "\n";}
print "C\n";
foreach my $tmp2 (@c) { print "#->" . $tmp2 . "\n";}
Esto muestra por pantalla:
B
#->Jueves
#->Lunes
#->Martes
#->Miercoles
#->Viernes
C
#->Viernes
#->Jueves
#->Miercoles
#->Martes
#->Lunes
También se pueden utilizar hashes:
$b{'ciudad'} = "ciudadano";
$b{'bonaero'} = {"pedro","eugenia","sandra","leandro"};
Esto es algo complejo al principio, pero resulta muy útil para evitar jugar con varios sets de variables. Para la llave 'ciudad el valor del hash es "ciudadano".
Pero para "bonaero", esto no es una variable, si no un array.
Si se hace algo como:
$_ = "Hola Mundo";
print;
Esto muestra un simple "Hola Mundo" por pantalla. Esto se debe a que el $_ es una variable especial para Perl, es una variable "por defecto".
Antes se vieron ejemplos como:
my $var = "valor";
Esto define la variable $var y le asigna una cadena de caracteres "valor".
Si se hace algo como:
#!/usr/bin/perl -w
my $a = "valor";
if ($a =~ m/val/){
my $b = "nada";
$a = $b;
print $b;
}
print $a;
print $b;
La ejecución de este código da error:
Name "main::b" used only once: possible typo at scope_1.pl line 10.
Use of uninitialized value in print at scope_1.pl line 10.
Y es porque se está llamando a $b fuera del ciclo donde se definió.
Es como en cualquier lenguaje:
if (<condición de verdad/falsedad>){
....
}elsif(<otra condición>){
....
}else{
....
}
En Perl también está la negación:
unless (<condición>){
....
}
El código (....) lo ejecutará siempre y cuando la <condición> sea falsa.
En muchos lenguajes de programación modernos se derine una de las dos, y la otra se la define como la negación de la anterior. En perl se pueden entender esto haciendo:
#!/usr/bin/perl -w
my $i = 0;
if ($i++){
print "Primera vez\n" . $i . "\n";
}elsif($i++){
print "Segunda vez\n" . $i . "\n";
}unless($i++){
print "Tercera vez\n" . $i . "\n";
}
__END__
La primera vez que se pregunta, el valor de la <condición> es igual a cero, por eso no hace nada (cero es la falcedad). El resto de las veces la <condición> es verdad, por eso entra, salvo cuando en vez del if es unless, que busca que sea falsa la <condición>.
En otras palabras, a Perl solo le importa que algo sea falso, el resto de los valores, los toma como verdadero (o sea, que el valor verdadero es todo aquello que no sea falso).
Ese último código introduce algo que es las "auto-sumas":
my $i = 0;
if ($i++ == 0){
print "Ahora es $i\n";
}
print "Y ahora es $i\n";
Si yo ejecuto eso sale por pantalla:
matias@carosa:~/Proyectos/perl/20051013$ ./auto_suma.pl
Ahora es 1
Y ahora es 1
matias@carosa:~/Proyectos/perl/20051013$
Pero con una leve modificación:
my $i = 0;
if ($i++){
print "Ahora es $i\n";
}
print "Y ahora es $i\n";
Ahora aparece:
matias@carosa:~/Proyectos/perl/20051013$ ./auto_suma.pl
Y ahora es 1
matias@carosa:~/Proyectos/perl/20051013$
Esto se debe a que la linea:
if ($i++ == 0){
El condicional verifica la condicion de verdad de la expresión, con lo cual debe evaluar la expresión internamente. La expresión es una igualdad, tiene que evaluar los dos términos de la igualdad, el primero, luego de evaluarlo, le suma uno, y luego evalua al segundo, con lo cual la comparación de los dos es verdadera, porque el primner término de la igualdad, estaba en cero al compararlo con el segundo término, pese a que si se lo vuelve a evaluar es falso.
Por ejemplo:
#!/usr/bin/perl -w
my $i = 0;
if ($i++ == $i++){
print "Ahora es $i\n";
}
print "Y ahora es $i\n";
Al ejecutarlo:
matias@carosa:~/Proyectos/perl/20051013$ ./auto_suma_3.pl
Y ahora es 2
matias@carosa:~/Proyectos/perl/20051013$
#!/usr/bin/perl -w
my $b = 0;
while ($b++ < 10){
print "B es $b\n";
}
__END__
Y también existe la negación del while:
#!/usr/bin/perl -w
my $b = 11;
until ($b-- < 1){
print "B es $b\n";
}
__END__
(le sumé uno para que la salida quedara parecida al anterior).
El for es igual al de C:
#!/usr/bin/perl -w
for (my $i = 0; $i < 10; $i++){
print "#-> $i\n";
}
#!/usr/bin/perl -w
my @arr = ("a","b","c");
foreach (@arr){
print "Letra: '$_'\n";
}
También se puede utilizar el foreach sin utilizar el $_:
#!/usr/bin/perl -w
my @arr = ("a","b","c");
foreach my $letra (@arr){
print "Letra: '$letra'\n";
}
Las salidas de ambos programas son las mismas.
Algunos operadores matemáticos son:
Comparación numérica:
Comparación de cadenas de caracteres:
Operadores booleanos:
Otros operadores destacables:
Como en Java y otros lenguajes, algunos operadores básicos se pueden combinar, por ejemplo (pero no limitado a):
$a += 3; # igual que $a = $a + 3
$a -= 3; # igual que $a = $a - 3
$a .= "\n"; # igual que $a = $a . "\n";
Para leer un archivo basta con:
#!/usr/bin/perl -w
open(ARCH,"$0");
while (my $linea = <ARCH>) {
print $linea;
}
close(ARCH);
Este programa al ejecutarlo, se lee a si mismo (el $0 es una variable especial, que indica el nombre del script).
En un contexto scalar (simple), al llamar a un manejador de archivos <ARCH>, devuelve solamente una línea (ver también el significado de $/), mientras que en un contexto de listas, devuelve el archivo total:
#!/usr/bin/perl -w
open(ARCH,"$0");
my @b = <ARCH>
print @b;
close(ARCH);
Esto hace lo mismo que el otro código, pero sin el while.
Se pueden tener varios manejadores de archivos (en inglés filehandlers), y utilizarlos de distintas formas con print.
print STDERR "Hay problemas\n";
print LOGFILE $error;
print OUTFILE $registro;
Esto lo que que hace es mostrar por pantalla (salida de error) la frace "Hay problemas\n". Guarda en el manejador de archivos LOGFILE la variable $error. Y por último guarda en el manejador de archivos OUTFILE la variable $registro.
Hay que tener en cuenta que se debería siempre cierrar los manejadores de archivos una vez que se terminan de utilizar, pero para ser honestos Perl tiene rutinas internas que intentan (mayormente con éxito) limpiar todo antes de terminar.
Uno de los puntos más fuertes que tiene Perl es el manejo de las expresiones regulares, y al mismo tiempo, es uno bastante complejo.
Lo más básico que se puede idear, es un típico caso de validación de una entrada de texto.
#!/usr/bin/perl -w
sub number {
my $valor = "";
print "Ingrese un valor entre cero y cien: ";
$valor = <STDIN>;
chop($valor);
unless(($valor =~ m/^(\d+)$/) && ($1 > 0) && ($1 < 100)){
print "El valor ingresado es incorrecto, intentelo nuevamente.\n";
number();
}else{
print "El numero ingresado fue: $valor\n";
}
}
## La unica funcion que hay:
number();
__END__
Este script incorpora algo muy útil, y es la modularización. El sub number (sub por subrutina) indica que todo ese bloque no será ejecutado hasta que sea invocado por su nombre, number(). Dentro de este módulo, lo que hace es preguntar un numero entre cero y cien, y guardarlo en un avariable ($valor), luego le saco el último caracter (que es el "\n"). Luego pregunto si no es igual a uno o más digitos (el \d+) y ese valor lo captura y se lo puede referenciar como $1. Con el valor $1 me fijo que sea mayor que cero y menor que 100, si no es así, doy un mensaje de error y pregunto nuevamente (en realidad se ejecuta otra vez el módulo). Si está entre cero y cien, digo el valor.
Otras expresines regultares de utilidad:
También hay cuantificadores:
Ejemplo de substitución desde la línea de comandos usando el modificador -p:
matias@carosa:~/Proyectos/perl/20051013$ cat texto_2.txt
Chau Mundo!!
matias@carosa:~/Proyectos/perl/20051013$ perl -pes/Chau/Hola/< texto_2.txt
Hola Mundo!!
Obteniendo la hora, minutos y segundos del comando date (shell):
matias@carosa:~/Proyectos/perl/20051013$ perl -e$ARGV[3]=~/(..):(..):(..)/;`date `
print "Hora: $1\nMinutos: $2\nSegundos: $3\n"
if (($1 != "") && ($2 != "") && ($3 != ""));
Hora: 19
Minutos: 39
Segundos: 30
Aquí hay algo para destacar, y es el uso de los argumentos que se pasan en la línea de comandos, y esto lo podemos utilizar con una variable propia de Perl: $ARGV.
La variable @ARGV es un array que contiene todos los argumentos que le pasemos a perl, desde el primero (índice 0) hasta el último (índice $#ARGV).
Comentarios
Enviar un comentario nuevo