Tutorial de PERL en castellano : Ahorrando energías

Preguntas frecuentemente preguntadas
Bibliografía.
Recursos Internet
Recordando, que es gerundio

Operadores, matrices y la variable por defecto $_

Como nuestro político corrupto, por su experiencia en el ramo de la construcción, ha sido nombrado delegado de Obras Públicas, tiene que pasar la mayor parte del tiempo visitando carreteras, caminos, puentes y veredas. Nada mejor, pues, que comprar un portátil AMD K6-2 para ir introduciendo las mordidas en el propio lugar donde se originen. El problema es el limitado rango de las baterías, que hacen que si hay que viajar de Albacete a Cuenca, se gaste la batería a la altura de Motilla del Palancar. Para ahorrar energía, decide modificar su programa de forma que escriba menos en el disco; es decir, que cargue todos los datos en memoria, y los guarde sólo cuando termine el bucle. Además, para no poner la excusa a la comisión del Congreso (que ya pide Anguita a voces) de que no se acuerda de nada, decide grabar también las fechas y horas de los sucesos. Escribe, con su pericia creciente en Perl, el programa memoria.pl (listado 3).

until(0) {
2      print "Cliente\n";
3      chop( $paganini = <STDIN>);
4      last if !$paganini;
5      print "Valor inmueble\n";
6      chop($valor = <STDIN>);
7      $comision = $valor * 0.25;
8      ($seg, $min, $hora, $dia, $mes, $anho, @zape) = localtime(time);
9      $mes++;
10      $anho+=1900;
11      $zipi = "$paganini $comision $hora:$min $dia/$mes/$anho\n";
12      push( @mem, $zipi );     
13 };
14 
15 open (MANTA,">clientes.mas");
16 foreach (sort @mem ) {
17      print MANTA;
18 }
19 close (MANTA);
Listado : Programa memoria.pl

En esta pequeña modificación del programa anterior, y en la línea 8, se introduce una nueva estructura de Perl: el array o lista. Un array se indica con el símbolo @ (arroba), aunque a cada elemento de un array nos referiremos con la notación $mem[0], ya que es un escalar. En general, tanto los operadores como las funciones en Perl se comportan de forma diferente si se trata de un entorno escalar o si se trata de un entorno de lista o vectorial. En este caso, el operador localtime devuelve una lista compuesta por los segundos, minutos y demas, tomándolo de la función time que devuelve el número de segundos transcurridos desde hace mucho tiempo (1970, para ser exactos). Además, estamos utilizando la lista @zape para contener el resto de los elementos de la hora, que no nos interesan (serían el día de la semana y cosas así). Por supuesto, también se podría haber hecho de otra forma, mucho más larga

@fecha= localtime(time);
$seg = $fecha[0];
...

Las matrices empiezan en Perl en 0 habitualmente, como sucede en C; pero esto se puede cambiar (usando la variable global $[). Hay que tener cuidadito con la variable $anho, que devuelve, al contrario de lo que se pudiera pensar, el número de años transcurridos desde 1900. Eso da lugar a todo tipo de pequeños efectos 2000, que todavía se ven por algún sitio Web. Por eso, en la línea 10, se le suma 1900, para que dé el año actual con cuatro cifras. Tal como en el lenguaje C, $anho+=1900 equivale a $anho=$anho+1900;

En la línea 12 hay un nuevo operador, push. Este operador hace precisamente eso, achuchar un escalar o una lista al principio de otra lista (recordad que lista y array son prácticamente sinónimos). En este caso, estamos metiendo la cadena que hemos creado, $zipi, al principio de la matriz @mem (que, por cierto, tampoco hemos tenido que declarar ni dimensionar). Si queremos eliminar el primer componente de una matriz, se hace con el operador obvio, $cadena = pop(@mem);

En la línea 16 aparece una nueva orden de control de bucle: foreach, para cada, que repite el cuerpo del bucle para cada uno de los elementos de la lista que hay contenida entre paréntesis. Se puede abreviar por for, aunque también se puede comportar como lo hace en C. ¿Y cuál es la lista a la que se aplica? La que hemos creado anteriormente, pero por orden (de ahí el sort). En este caso la ordenará por orden alfabético, saliendo algo como esto

Uno 750 12:0 31/1/2000
otro 1402654 12:0 31/1/2000
otro mas 4020267 12:1 31/1/2000
y otro mas todavia 4040.25 12:1 31/1/2000

Sin embargo, dentro del bucle no parece que pase nada; y, ¿dónde diablos se ha metido la variable de bucle?. Lo que ocurre es que en estos casos Perl tiene una variable por defecto, $_, que es la variable de bucle por defecto y sobre la que actúan los operadores y funciones también por defecto. Es decir, que el bucle anterior equivaldría a

foreach $_ (sort @mem) {
    print MANTA $_;
}

Y aunque sé que ya estáis esperando que lo diga, se puede hacer de otra forma, esta vez menos Perlística; utilizando bucles normales y corrientes

for ($i = 0; $i<=$#mem; $i++) {
    print MANTA $mem[$i];
}

si bien en este caso el fichero de salida no estará ordenado. En este caso se utiliza la construcción $#<nombre de matriz>, que devuelve el último índice existente para esa matriz. Ojo, se trata del último índice, no del número de elementos de la matriz; por eso los bucles en Perl usan un <= para terminar.

  1. Hacer un programa que imprima su entrada estándar en orden inverso,empezando por la última línea y acabando por la primera. Se ejecutará con
     
    unix% cat <nombre del fichero> ¦invert.pl
    PistasUsar la orden pop, que extrae el primer elemento de un array. Reto Hacerlo en una sola línea.
  2. $. es una variable que contiene la línea del fichero de la que se está leyendo. Teniendo esto en cuenta, crear un filtro (es decir, un programa que lea de entrada estándar y escriba en salida estándar, tal como el anterior) que imprima un fichero con el número de línea al principio de cada una.
  3. Hacer un histo(pro)gra, es decir, un programa que recoja una serie de valores numéricos (con valores reales entre 0 y 100), los distribuya en cinco cubos (del 0 al 20, entre 20 y 40, y así sucesivamente), calcule las frecuencias de cada uno de los cubos, e imprima barras horizontales cuya longitud es función de la frecuencia.
Ejercicios

[ Preguntas frecuentemente preguntadas] [ Bibliografía.] [ Recursos Internet] [ Recordando, que es gerundio]