Curso de Perl

Mauricio A. Vasquez M.
mvasquez@dcc.uchile.cl

Septiembre de 1995
Actualizacion: Abril de 1997


Capitulo I : Introduccion

Perl que significa "Practical Extraction and Report Language" es un lenguaje de programacion medianamente nuevo, el cual surgio de otras herramientas de UNIX como son : sed,grep,awk,c-shell. Principalmente sirve para labores de procesamiento de texto, lo cual lo hace en una forma facil y clara, no como es en C o Pascal; tambien sirve para la programacion de software de sistemas; y ahora ultimo se ha consolidado como "el" lenguaje para programar aplicaciones para WWW , por ejemplo un programa que ponga en pantalla las notas de un alumno dada su matricula, etc. Por todas estas potencialidades es que estudiaremos Perl.

Nuetro primer programa sera el ya tipico, que imprime Hola, Mundo! :

La primera linea lo que hace es llamar al compilador de Perl.
La segunda linea imprime Hola, Mundo! y un cambio de linea(\n).
Debemos decir que todas las lineas (salvo contadas excepciones) de un programa en Perl terminan con ';' .

Veamos como lo ejecutamos, suponiendo que lo grabamos en un archivo llamado miarchivo.algo

   [%] chmod 755 miarchivo.algo
   [%] miarchivo.algo
       Hola, Mundo!
   [%]
Veamos un programa ahora en el cual se interactua con el usuario : En la segunda linea igual que antes se imprime un mensaje, pero ahora vemos que esta con '()', estos son opcionales. En la siguiente linea se introducen dos nuevos conceptos, primero el de variable ($name),- en el Capitulo II veremos que las variables (escalares) empiezan con '$'-; <STDIN> lo que indica es que se leera una linea desde la entrada estandard. En la cuarta linea la funcion chop() lo que hace es sacarle el ultimo caracter a $name, es decir le quita el Enter (cambio de linea). Y finalmente en la ultima linea lo saludamos, en esta vemos que $name toma el valor que se le ingreso.

Veamos un programa en el cual se eligen opciones :

En la tercera linea vemos el caracter '#' que significa comentario.En la quinta linea se introduce el if, el cual mediante el eq compara dos strings: $name y "Claudio"; hay que hacer notar que el cuerpo del if siempre va entra llaves(aunque sea una linea), al igual que el else, el cual significa que se imprime "Hola, $name\n" si no se cumplio la condicion del if.

Un ultimo programa, en el cual se introducen los ciclos:

En la 16a linea usamos el while, el cual al igual que en otros lenguajes significa que las lineas entre las llaves se repetiran mientras sea verdadera la condicion, la cual en este caso pregunta si $palabra no es igual a $palabrasec



Capitulo II : Datos escalares

En Perl existen dos tipos de datos, numeros y strings, pero entre los numeros estan los enteros y los reales.

Ej: 4,7.5,"hola"

Float : Ej: 1.25,4.25e45,-6.5e24,-1.2E-23

Integer : Ej: 12,15,-2004,3485
	      0377 # 377 octal <=> 255 decimal
              -0xff # ff negativo en hexadecimal <=> -255 decimal

Strings : Ej: "hola",'Como estas'
Para senalar los strings hay dos formas de hacerlo:

Como vimos en estos ejemplos en los double quoted strings, se reconocen cosas como \n,\t,etc. mientras que con single quoted no, pero tiene la ventaja de poder escribirse literalmente lo que se pone entre ellos.

Operadores

Conversion entre numeros y strings

"123.45juan" # si es operado como numero toma el valor 123.45
Ej: $a="3b";
    $b=$a+5; # $b=8
Conversion al reves :
Ej: $a=5;
    "x".$a  # "x5"

Variables Escalares

Una variable escalar es un nombre que mantiene un valor, en Perl las variables deben empezar con '$' .
Estrictamente son nombres para variables escalares:

Nombres de variables escalares
$[a-zA-Z]+[a-zA-Z0-9_]*
$[1-9]+[0-9]* (variables de patern matching)
$\,$/,$_,etc (variables especiales)

Ej:$a,$nombre

Operadores

Ej:$a=17;
   $b=$a+3;
   $b=$b*2;
   $a=4+($a=3); # $b=7,$a=3
   $d=$c=5; 

Interpolacion de variables escalares en strings

Si una variable es puesta en un string double quoted (") se interpola el valor de la variable.
Ej:$a="juan";
   $b="hola $a"; # $b="hola juan"
Y si una variable se pone entre single quoted (') no se interpola el valor de la variable.
Ej: $x="hola";
	$y='$x amigo'; # asigna '$x amigo' a $y
En los strings existen tambien algunos modificadores: \U,\u,\L
Ej: $mayjuan="\Ujuan"; # $mayjuan="JUAN" 
    $juan="juan"; $mayjuan="\U$juan"; # $mayjuan="JUAN"
    $capjuan="\u$juan"; # $capjuan=Juan
    $pedro="\LPEDRO"; # $pedro="pedro"
    $cappedro="\u\LPEDRO"; #cappedro="Pedro"
    $maypedro="PEDRO"; $cappedro="\u\L$maypedro"; # $cappedro="Pedro"

El valor undef

Que pasa si usamos una variable antes de darle un valor ? , nada fatal, se asigna como cero si es numero o "" si es como string.
Ej: $a=3;
	$b=$a+$c; # $b=3
    $x="hola";
    $y=$x.$z; # $y="hola"



Capitulo III : Arreglos

Un arreglo es una lista ordenada de datos escalares. Los arreglos pueden tener cualquier numero de elementos.

Representacion literal

Un arreglo es una lista de valores separados por coma, y dentro de parentesis. Los valores de los elementos pueden ser de distinto tipo.
Ej:   (1,2,3)
      ("juan",4.5)
Sus valores no necesariamente tienen que ser constantes, puede tener variables.
Ej: ($a,17)
    ($b+$c,$d+$e)
El arreglo vacio es representado por () .

Variables

Asi como las variables escalares se representan con un '$' al comienzo, las variables de tipo arreglo empiezan con '@'.
Ej: @a , @hola 

Operadores

Asignamiento:
Mediante el operador '=' le podemos dar a una variable arreglo un valor.
Ej:@a=(1,2,3);
   @b=("yo","tu",2);
   @c=@a; # copia el arreglo @a en @c
   @d=($x,$y);
El largo de un arreglo ( ej : @a ) queda guardado en $#a.

Ej:
@a=('b',3,"a");
$d=$a[$#a]; # $d='a'
$c=$#a+5;   # $c=7

Acceso a los elementos

Para enumerar los elementos de un arreglo se empieza desde el 0. El primer elemento del arreglo @a es $a[0], vemos que para accesar un elemento especifico del arreglo ya no se ocupa '@'.
Ej: @a=(7,8,9);
    $b=$a[0]; # asigna 7 a $b
    $a[1]=5; # ahora @a es (7,5,9)
    $a[2]++; # suma uno al tercer valor de @a siendo ahora (7,5,10)
    $c=$a[0]+$a[1];
Hasta ahora solo hemos visto que los indices de los arreglos son constantes, pero tambien pueden ser variables.
Ej:@juan=(7,8,9);
   $a=2;
   $b=$juan[$a];
   $c=$juan[$a-1]; # $c=8
   $d=$a[$#a]; # $d=9
Si uno accesa un elemento del arreglo mas alla del fin del arreglo el valor undef es retornado.
Ej: @a=(1,2,3);
    $b=$a[7]; # $b es 0 o "" , dependiendo del contexto
Asmismo, asignar un valor a un elemento mas alla del fin del arreglo, lo que hace es agrandar el arreglo poniendo undef a los valores intermedios.
Ej: @a=(1,2,3);
    $a[3]="hola"; # @a es ahora (1,2,3,"hola")
    $a[6]="chao"; # @a es ahora (1,2,3,"hola",undef,undef,"chao")

Operaciones sobre arreglos

Push y Pop

Una comun utilizacion de los arreglos es como stacks, donde los nuevos valores son agregados y borrados por el lado derecho del arreglo. Push() es utilizado para agregar elementos y pop() para sacar.
Ej: @lista=(1,2,3);
    push(@lista,5); # @lista=(1,2,3,5)
    $a=pop(@lista); # $a=5, @a=(1,2,3)

Shift y Unshift()

Al igual que Pop y Push estos sacan y meten elementos de un arreglo, pero lo hacen por el lado izquierdo.
Ej: @a=(1,2,3);
    unshift(@a,0); # @a=(0,1,2,3);
    $x=shift(@a); # $x=0 , @a=(1,2,3)  
    unshift(@a,5,6,7) # @a=(5,6,7,1,2,3)

El operador reverse

reverse() invierte el orden de los elementos de un arreglo, retornando la lista invertida.
	
Ej: @a=(1,2,3);
    @b=reverse(@a); # @b=(3,2,1)   
    @c=reverse(1,2,3); # lo mismo
Notemos que la lista que se le pasa como parametro permanece inalterable. Si nosotros queremos dejar la lista invertida ahi mismo debemos hacer : @a=reverse(@a)

Sort

Sort toma una lista y la ordena ascendentemente ( segun codigo ASCII ) y retorna la lista ordenada.
Ej: @a=sort("grande","pequeño","chico"); # @a=("chico","pequeño","grande");
    @b=(1,2,4,8,16,32,64);
    @c=sort(@b); # @c=(1,2,16,32,4,64,8)
Como vemos en este ultimo ejemplo sort()ordena por strings, no numericamente.

Chop

chop() trabaja igual que en variables escalares, le saca el ultimo caracter a cada elemento del arreglo.
Ej: @a=("hola","mundo\n","felices dias");
    chop(@a); # @a=("hol","mundo","felices dia")

Operaciones raras

@a=(1,2,3,4,5);
($b,$c,$d)=@a;    # b=1 c=2 d=3

@a=(1,'b',2,'c'); ($b,@a)=@a; # b=1 a=('b',2,'c')
@a=('hola','tu'); @b=(1,2,@a,7,8); # b=(1,2,'hola','tu',7,8)
@a=(1,2,3,4,5); @b=@a[1,3]; # b=(2,3,4)
@b=(1,2,3,4,6)[0,1]; # b=(1,2)
@a=(7,8,9); @b=(1,2,0); @c=@a[@b]; # c=(8,9,7)



Capitulo IV :Estructuras de control

Al igual que en la mayoria de los lenguajes de programacion , en Perl existen estructuras como if, for, while.

if,elseif,else

La estructura de un if es la siguiente :
if ( .... ) {
    ......;
    ......;
}
elsif ( .... ) {
    ......;
    ......;
}
elsif ( .... ) {
    ......;
    ......;
}
else ( .... ) {
    ......;
    ......;
}
Notemos que los elsif y el else van solo si el usuario desea varias preguntas, se podria usar por ejemplo :
if ( $a < 18 )
{
print "Tu eres menor de edad\n";
}
else
{
print "Eres un adulto\n";
}
o :
if ( $a == 0 )
{
$ind++;
print "Incorrecto\n";
}
Digamos tambien que aunque sea una instruccion por if debe ir entre llaves.

While y until

La forma del while es :
while ( condicion ) {
....;
....;
}
Lo que esta entre llaves se ejecuta mientras sea veradera la condicion.
Ej: print "Cuantos años tienes?";
    $a=<STDIN>;
    chop($a);
    while ( $a > 0 )
       {
       print "El año pasado tenias $a años\n";
       $a--;
       }
La forma del until es :
until ( condicion ) {
...;
...;
}
A diferencia del while el until se ejecuta al menos una vez , y se sigue mientras la condicion sea falso , es decir es similar al Repeat/Until de Pascal.

For

La forma general del for es :
for ( exp_inicial; exp_testeo; exp_increm){
...;
...;
}
Ej: for ( $x=0;$x<10;$x++)
       {
       print "Llevas $x puntos\n";
       }

Foreach

El foreach de Perl es muy similar al de C-shell , recibe una lista de valores y asigna cada uno de los valores de la lista a una variable de lectura . La estructura del foreach es :
foreach $a ( @alguna_lista ) {
...;
...;
...;
}
Ej:@a=(3,5,7,9);
   foreach $x (@a) {
      $y=$x*3;
      print "$y\n";
      }
Imprime 9,15,21,27 .

If y unless

Hemos visto que todas las estructuras de control necesitaban de llaves, aunque solo fuera una instruccion; pero esto es incomodo por ejemplo para los if, es por eso que el if se puede usar de otra forma, poniendolo al final de lo que queremos ejecutar:
Ej:
print "Aqui es, Paulina" if ( $user eq 'Paulina' );
Tambien existe el unless, que hace todo lo contrario del if, es decir, ejecuta la accion si no se cumple la condicion del final:
Ej:
$a=45 unless ($a < 12 ); # b valdra 45 si a>=12



Capitulo V : Archivos

En este capitulo no solo veremos archivos, tambien algo de Entrada Standard y del paso de parametros a un programa.

Entrada estandard

Como ya dijimos para leer una linea desde la entrada estandard se debe asignar una variable escalar a <STDIN>
Ej:$a=<STDIN>; # guarda en $a la linea leida 
   chop($a); # le sacamos el enter que tienen todas las lineas por su
			   ingreso
Como procesar toda la entrada estandard ?:
while ( $a=<STDIN> ) 
{
manejo de la linea leida ..... ;
}
El while termina cuando ya no encuentra una linea ingresada desde la entrada estandard.
Otra forma de hacer esto ultimo ( procesar toda la entrada est. ) es asignar <STDIN a una variable de tipo arreglo Ej : @b=<STDIN> ; # en $b[0] guarda la 1a linea, en $b[1] la 2a ....

Lectura de parametros pasados a un programa

Dentro de un programa en Perl los argumentos que se le pasan quedan guardados en el arreglo @ARGV .
Ej: %vi prog1.pl
    #!/usr/local/bin/perl
    print "Tu ingresaste las palabras:\n";
    for($x=0;$x<$#ARGV;$X++)
       {
       print "$ARGV[$x]\n";
       }
    %chmod 755 prog1.pl
    %prog1.pl hola mundo chao
      Tu ingresaste las palabras:
      hola
	  mundo
	  chao
    %

Procesamiento de archivos

Como en todo lenguaje en Perl se puede trabajar con archivos. Lo primero que se hace es abrirlo y luego leerlo :
Ej: open(FILE,"file1");
    while ( $a=<FILE> ){
    .....;
    }
    close(FILE);
Lo que hicimos en la 1a linea es abrir el archivo de nombre file1 y a ese archivo le asignamos el "file handler" : FILE ( debe ser cualquier nombre pero en mayuscula ) . Luego con el while vamos leyendo linea a linea ( tambien podriamos haberlo hecho como con <STDIN> de asignar una variable de tipo arreglo a <FILE> y habriamos leido el archivo de una pasada ) . Finalmente algo muy importante, es cerrar el archivo .

Por supuesto tambien podemos escribir en un archivo.

Ej:
$file='hola.c';
open (A,">$file");
# Abrimos para solo escritura el archivo hola.c
print A "hola\n";
close(A);
Tambien podemos hacer append a un archivo:
Ej:
@l=('a',"\n",'b',"\n");
open(G,">>/user/jperez/d.txt");
# Abrimos para escritura pero append
print G @l;
close (G);
Veamos dos ejemplos mas interesantes:
Ej:
open (A, "file") || die "No se puede abrir\n";
                      |
                      |
                    vale 1
Un programa que simula 'cp'
$#ARGV != 2 || die "use a.pl origen destino";
open (A,"$ARGV[0]")||die("No se puede leer el origen");
open (B,">$ARGV[1]")||die("No se puede escribir en el destino");
while(  )
   {
   print B || die "No se pudo escribir";
   }

Inclusion de archivos

Al igual que en C, uno puede incluir otro archivo con codigo perl.
Con require incluimos un archivo, el cual no necesariamente tiene que tener un 'main', es decir pueden ser solo subrutinas.
Ejemplo:
#!/usr/local/bin/perl

require "otroarchiv.pl";
# sirve para agregar 
# el codigo que esta en el archivo otroarchiv.pl 
Otra forma es con eval, el cual en realidad no sirve en si para incluir archivos, sino que evalua expresiones.
Ejemplo:
$exp='$nombre="juan"; $apellido="perez"; $nombre.=$apellido; print "hola $name\n";';
eval $exp;
# imprimira 'hola juanperez'
Entonces usando eval, podriamos incluir un archivo y que se ejecute:
$arch=`cat archivo`;
$eval $arch;



Capitulo VI: Arreglos asociativos

Son igual a los arreglos pero los indice ya no son numeros enteros, pueden ser cualquier cosa. Y asi como los arreglos en su totalidad se denotaban con '@', aca es con '%'.

Ejemplos:

$l{'luis'}='lucho';
$l{'jose'}='pepe';
$a='francisco';
$b='pancho';
$l{$a}=$b;

Lo mismo del ejemplo anterior lo podriamos haber hecho asi:
%l={'luis'=>'lucho','jose'=>'pepe','francisco'=>'pancho'};

foreach $x (%l)
   {
   # Imprimimos el indice y el contenido
   print $x;
   }

%m={'uno'=>'1','dos'=>'2'};
print %m;

uno1dos2

foreach $k ( keys %m)
# keys retorna un arreglo con las llaves del
# arreglo asociativo pasado
   {
   print "llave:$k,contenido:$m{$k}\n";
   }

foreach $k ( sort keys %m)
# sort ordena (keys %m) que es un arreglo que
# contiene las llaves de %m
   {
   print "$k:$m{$k}\n";
   }

dos:2
uno:1



Capitulo VII : Expresiones regulares

En Perl se usa la misma notacion para expresiones regulares de sed y grep :
   .      ->  cualquier caracter
   [e.r]* -> 0 o mas veces e.r.
   [e.r]+ -> 1 0 mas veces e.r.
   ^      -> comienzo de linea
   $      -> fin de linea
   [^e.r] -> no e.r.
Para dar una expresion regular se pasan en '/'. Y para aplicarla a una variable se usa el operador '=~'.
Ejemplos : $a="hola mundo";
           $e="chao";
           $b= ($a =~ /^he/); # $b vale true = 1                
           $c= ( "chao" =~ /ah/ ) ; # $c=0
           $d= ( "$e" =~ /ah/ ); # $d=0
           if ( $a=~ /o$/ )
               { print "Correcto\n"; } # imprime Correcto
El operador '=~' tiene una opcion que lo que hace es como el sed, reemplazar un trozo de texto por otro, esa opcion es la 's' :
El formato es $x =~ s/expant/expnueva/ ;
Ej: $cual="este es un test";
	$cual =~ s/test/prueba/; # $cual ahora es "este es un prueba"

Split() y Join()

Split()

Split() lo que hace es dado un separador, separa un string en un arreglo :
Ej: $linea="mvargas::117:10:Juan";
    @a=split(/:/,$line); # @a=("mvargas","","117","10","Juan")

Join()

Join() hace lo inverso de Split(), dado un arreglo lo junta en un string, separado por un delimitador especificado.
Ej:@campos=(1,2,"hola");
   $salida=join(".",@campos); # $salida="1.2.hola"



Capitulo VIII : Interfaz con Unix

Al igual que en c-shell o C dentro de un programa en C se puede ejecutar un comando UNIX, o un programa propio en cualquier lenguaje, esto se hace con system(), y de otra forma con '`'.
Ej: #!/usr/local/bin/perl
	print "En el archivo listado dejaremos la lista de archivos\n";
    system("ls -l > listado");
Ej: #!/usr/local/bin/perl
    $num=`wc -c listado`; # en la var. $num deja el numero de caracteres que
							tiene el archivo listado
Nota: Es importante decir que dentro de '`' y system son expandidos los valores de las variables.
Ej:$a="direct1";
   @a=`ls -l -a $a`;
Aqui introducimos un nuevo concepto, resulta que despues de la ejecucion de estas lineas en el arreglo @a quedan guardadas las lineas de salida del comando ls -l -a direct1 .

Existe otra forma de ejecutar comandos Unix, es con el open, el cual tambien tiene las funcionalidades del popen de C, es decir podemos abrir para escribir o leer, un comando:

Ej:
open(FD,"ls |");
@archivos=;
close(FD);
# lo que hizo fue guardar todo lo que retorno el ls
# en el arreglo @archivos, un nombre de archivo en
# cada casilla del arreglo
Tambien podemos escribir en un comando:
Ej:
open(FE,"| sed 's/[,;:.]//g' > salida");
for($x=1;$x<=5;$x++)
  {
  print FE $lin[$x];
  }
close(FE>
# a 5 strings les aplicamos un sed, el cual les elimina
# la puntuacion; el resultado lo deja en el archivo salida



Capitulo IX : Subrutinas

Al igual que la mayoria de los lenguajes de Programacion, Perl soporta subrutinas, tambien conocidas como procedimientos o funciones.
Con ejemplos, veremos como se construyen.

Ejemplo 1

sub suma {
local($x,$y)=@_;
return($x+$y);
}
# En @_ se reciben los parametros (es por valor)
$f=8;
$c=&suma(4,$f);
# Si yo la hubiera llamado asi: $c=&suma(4,$f,'hola');
# igual funciona
# $c=12

Ejemplo 2

sub duplica() {
$x*=2;
}
$x=8;
&duplicar();
# $x=16, ya que no lo declaramos como 
# local en la subrutina =>
# duplica a x 

Ejemplo 3

for($x=0;$x<=n!;$x++)
# este for termina aprox. en n iteraciones,
# ya que se modifica en cada una de ellas
   {
   $y=&duplica($x);
   }
                                              
sub duplica {
$x*=2;
}

Como vimos el paso de parametros es por referencia, pero al igual que en C, los parametros se pueden modificar, via punteros:
Ejemplo 1

&inicializa(*arr);

sub inicializa {
local(*a)=@_;
$a[0]='cero';
$a[1]='cero';
$a[2]='cero';
}

Ejemplo 2

$st='uno:1,dos:2,tres:3';
&crea($st,*a);
# ahora: $a{'uno'}=1, $a{'dos'}=2, $a{'tres'}=3


sub crea {
local($pal,*g)=@_;
local($x,$a,$b);
local(@aux);
@aux=split(/,/,$pal);
for($x=0;$x<=$#aux;$x++)
   {
   ($a,$b)=split(/:/,$aux[$x]);
   $g{$a}=$b;
   }
}                                                  



Bibliografia

1