por Guido Socher Sobre el Author: Guido es un veterano fan de Linux y hacker de Perl. Su página sobre Linux se encuentra en www.oche.de/~bearix/g/ Contenidos: |
Resumen:
Perl parte I ofreció una primera visión general de Perl. En Perl parte II se escribió el primer programa útil. La parte III se centrará en el estudio de los arrays.
Veamos un ejemplo:
!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et: # declaración de una nueva variable de array: my @miarray; # inicialización de la variable con algunos datos: @miarray=("dato1","dato2","dato3"); # acceso al primer elemento (el de índice 0): print "el primer elemento de miarray es: $miarray[0]\n"; |
Obsérvese que escribimos @miarray para referirnos a todo el conjunto, y $miarray[0] para referirnos a elementos individuales.
En Perl, los arrays comienzan en el índice 0. Según se añaden datos, se van creando automáticamente nuevos índices, de modo que no es necesario conocer el tamaño del array en el momento de la declaración.
Se puede inicializar un array con una serie de datos sin más
que listar esos datos separados por comas y entre paréntesis. Por
ejemplo, ("dato1","dato2","dato3") es en realidad un array anónimo
(es decir, sin nombre). Por tanto, podemos poner ("dato1","dato2","dato3")[1]
para referirnos a su segundo elemento:
!/usr/bin/perl -w
print "El segundo elemento es:" print ("dato1","dato2","dato3")[1]; print "\n" |
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et: my @miarray =("dato1","dato2","dato3"); my $varb; my $i=0; foreach $varb (@miarray){ print "el elemento número $i es $varb\n"; $i++; } |
La ejecución del programa anterior produce la siguiente salida:
el elemento número 0 es dato1
el elemento número 1 es dato2 el elemento número 2 es dato3 |
La instrucción foreach toma cada elemento del array y lo asigna a una variable de bucle ($varb en el ejemplo anterior).
Es importante destacar que los valores de los elementos del array no se copian directamente a la variable de bucle. Por el contrario, la variable de bucle es una especie de puntero, de modo que cualquier modificación que sufra se refleja en los elementos del array.
El siguiente programa pasa a mayúsculas todos los elementos del
array. La instrucción de perl tr/a-z/A-Z/, similar a su homónima
de Unix, pasa todas las letras a mayúsculas.
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et: my @miarray =("dato1","dato2","dato3"); my $varb; print "antes:\n"; foreach $varb (@miarray){ print "$varb\n"; $varb=~tr/a-z/A-Z/; } print "\ndespués:\n"; foreach $varb (@miarray){ print "$varb\n"; } |
Ejecutemos el programa anterior. En el segundo bucle se aprecia todos
los elementos de @miarray han sido pasados a mayúsculas:
antes: dato1 dato2 dato3 después: DATO1 DATO2 DATO3 |
En Perl, el contenido de la línea de comando se asigna a un array llamado @ARGV. La función &getopt se limita a leer los valores de los elementos de @ARGV.
A diferencia de C, el contenido del primer elemento del array no es el nombre del programa, sino el primer argumento de la línea de comando (si se desea conocer el nombre del programa, entonces debe recurrirse a $0, pero esto sería objeto de otro artículo...).
He aquí la salida de un programa de ejemplo llamado suma.
Lee dos números en la línea de comando y los suma...:
> suma 42 2
42 + 2 es:44 |
... y éste es el código del programa:
#!/usr/bin/perl -w
# se comprueba si hay dos argumentos: die "USO: add numero1 numero2\n" unless ($ARGV[1]); print "$ARGV[0] + $ARGV[1] es:", $ARGV[0] + $ARGV[1] ,"\n"; |
#!/usr/bin/perl -w
my @miarray =("dato1","dato2","dato3"); my $varb; print "el array:\n"; foreach $varb (@miarray){ print "$varb\n"; } push(@miarray,"a"); push(@miarray,"b"); print "\ndespués de añadir \"a\" y \"b\":\n"; while (@miarray){ print pop(@miarray),"\n"; } |
pop elimina elementos del final del array, y el bucle while se sigue ejecutando hasta que el array esté vacío.
He aquí un programa
sencillo que busca en el directorio actual el nombre de un fichero
determinado:
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et: die "Uso: busca_en_dir_actual fichero\n" unless($ARGV[0]); opendir(DIRHANDLE,".")||die "ERROR: no se puede leer directorio actual\n"; foreach (readdir(DIRHANDLE)){ print"\n"; print "encontrado $_\n" if (/$ARGV[0]/io); } closedir DIRHANDLE; |
Echemos un vistazo al programa. En primer lugar, se comprueba si el usuario ha proporcionado un argumento en la línea de comando. Si no es así, se muestra información de ayuda y se sale del programa.
Seguidamente, se abre el directorio actual ("."). opendir es similar las funciones open para ficheros. El primer argumento es un handle (identificador), que es necesario pasar a las funciones readdir y closedir. El segundo argumento es la ruta al directorio.
Ahora viene el bucle foreach. Nótese que en este ejemplo no hay variable de bucle. Perl crea automáticamente una variable de bucle llamada $_. readdir(DIRHANDLE) devuelve un array, y entonces se usa foreach para examinar cada uno de sus elementos.
Mediante /$ARGV[0]/io se comparan las expresiones regulares contenidas en $ARGV[0] con la variable $_. El io significa que la búsqueda ignora mayúsculas y minúsculas, y que la expresión regular se compila sólo una vez. Esto último hace que el programa se ejecute más rápidamente. Conviene proceder así cuando se tenga una variable dentro de una expresión regular y se esté seguro de que el valor de esta variable no cambiará durante la ejecución del programa.
Probemos el programa. Supongamos que tenemos en el directorio actual los ficheros article.html, array1.txt and array2.txt. Pues bien, una búsqueda de "HTML" se haría de la siguiente forma:
>busca_en__dir_actual HTML . .. article.html found article.html array1.txt array2.txtNótese que la función readdir ha encontrado dos ficheros más: "." y "..". Se trata, como sabemos, del directorio actual y de su directorio padre.
¿Cómo podemos construir este programa? Ya tenemos código para leer el directorio actual y buscar ficheros en él. Habrá que comenzar en el directorio actual y, cuando nos encontremos un fichero que a su vez es también un directorio (excepto . y ..), buscar también en él.
Este sería el pseudocódigo de este típico algoritmo recursivo:
sub busca_fich_en_dir(){ my $dir=shift; ...leer el directorio $dir .... ...si un fichero es a su vez un directorio entonces ejecuta &busca_fich_en_dir(ese fichero).... }Obsérvese que para comprobar si un fichero es un directorio y no un enlace simbólico a un directorio, se usa:
if (-d "$file" && ! -l "$dir/$_"){....}.
Ya tenemos toda la funcionalidad que necesitamos, de modo que podemos
escribir el código fuente
(pff.gz).
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et: # autor: guido socher, copyright: GPL # &help unless($ARGV[0]); &help if ($ARGV[0] eq "-h"); # comenzamos en el directorio actual:
pff busca en el directorio actual y todos sus subdirectorios
EJEMPLO:
|
Examinemos el programa. En primer lugar, se comprueba si el usuario ha proporcionado un argumento en la línea de comando. Si no es así, se trata de un error, por lo que imprimimos un texto de ayuda para el usuario. También se imprime un texto de ayuda si se ha indicado la opción -h.
La búsqueda se inicia en el directorio actual. Se usa el algoritmo recursivo descrito anteriormente: leer el directorio, buscar los ficheros, comprobar si un fichero es un directorio, si lo es ejecutar de nuevo busca_fich_en_dir().
En la instrucción que comprueba los directorios, se comprueba también que no se trata de un enlace (link) a otro directorio. Es necesario hacer esto porque alguien podría haber creado un enlace simbólico a "..", lo cual haría que el programa se ejecutara indefinidamente.
"eq" es el operador de comparación de cadenas de perl. Mediante
next if ($_ eq "." || $_ eq "..");
se comprueba si el contenido de la variable $_ es igual a ".." o ".". Si es igual, se ejecuta la instrucción "next". Dentro de un bucle foreach, una instrucción "next" significa "volver al comienzo del bucle, pero usando el siguiente elemento del array". Es similar a la instrucción "continue" del lenguaje C.
Contactar con el equipo de LinuFocus
© Guido Socher LinuxFocus 1999 |
Translation information:
|
1999-11-10, generated by lfparser version 0.6