Entrada / Salida

Perl interactúa con el usuario o con el sistema operativo por medio de entradas salidas que permiten el intercambio de información. Este intercambio de datos se gestiona por medio de operadores específicos que configuran una interfaz entre el script y su entorno.

1. El acceso a archivos en Perl.

Perl accede a los archivos de tipo ASCII por medio de punteros a archivos. Estos se referencian mediante variables y constituyen el enlace entre el script y el archivo consultado. Se utilizarán mayúsculas para representar estas variables a fin de no equivocarse con otras variables. Los archivos se consultan mediante la rutina open que admite dos argumentos, un puntero de archivo y un nombre de archivo:

open(PUNTERO, "modo de acceso + nombre de archivo");

El argumento de open que representa el nombre de archivo puede tener cualquiera de los prefijos que se muestran en la siguiente tabla, estos prefijos indican el modo de acceso al archivo (si no se pone ningún prefijo es que se toma el modo de acceso por defecto que es el de lectura):

Modos de acceso a los archivos

En cuanto a los punteros a archivos decir que, cuando se ejecuta un programa en Perl su primera actividad es asignar un puntero o manejador de archivo para el canal de entrada, otro para el canal de salida y otro para el de información de errores. Estos punteros son respectivamente STDIN, STDOUT y STDERR, donde se puede observar que STD significa estándar. Los tres STD se usan con tanta frecuencia en Perl que a menudo se suponen que existen, y por consiguiente, Perl no necesita que se mencionen explícitamente, en lugar de ello, Perl los crea y les asigna canales automáticamente. Por ejemplo:

print "hola";
print STDOUT "hola";

Estas dos líneas realizan lo mismo ya que Perl supone que STDOUT es el monitor y por eso visualiza sin necesidad de indicar en ningún lugar STDOUT.

En el ejemplo que se puede ver a continuación, forzamos un error muy típico en los progrmadores no cerrar comillas:

print "hola;

El resultado de la ejecución de este programa será un mensaje paracido a este:

Can't find string terminator...line 3

Sabemos que con el simbolo > podemos redirigir una salida de pantalla a un archivo. Pero si tecleamos:

hola.pl > error.txt

El archivo error está vacío. Esto es porque la salida estándar de los errores STDERR es la pantalla. Para que se grave el error en el archivo hay que direccionar el canal de error, que en Unix es el 2, al archivo. Esto se hace como sigue:

hola.pl 2>error.txt

2. El operador de entrada <>.

Una vez iniciado el puntero mediante la rutina open, este mismo puntero permite acceder al contenido del archivo por medio del operador <>. El contenido del archivo se recorre línea por línea mediante la estructura <PUNTERO>. Al final de la utilización el archivo se cierra mediante el operador close. El ejemplo siguiente indica como acceder al contenido del archivo data.txt y guardar el resultado en el archivo out.txt:

open(IN, "data.txt");
open(OUT, ">out.txt");
while($linea = <IN>) {
  # manipula los caracteres leidos y puestos en la variable
  # $linea. Por ejemplo convertir los caracteres a minúsculas
  $linea =~ tr/A-Z/a-z/;
  # escritura del resultado
  print OUT $linea;
}
close(IN);
close(OUT);

El ejemplo siguiente visualiza en la consola el nombre  de cada usuario y su directorio predeterminado. Esta información se extrae del archivo "/etc/passwd" que contiene la descripción de cada login. Para ello es necesario saber que cada línea del archivo passwd está compuesta por: el nombre que usa el usuario para entrar (login), la contraseña encriptada (password), número que identifica al usuario (uid), número que identifica al grupo al que pertenece el usuario (gid), información sobre el usuario (User_Information), directorio inicial del usuario (login_directory) y el interprete de comandos usado por dicho usario (login_shell). Esta información relativa al usuario se estructura en dicho fichero en una línea de la siguiente manera:

login:password:uid:gid:User_Information:login_directory:login_shell

Por tanto, este ejemplo se realizará de la siguiente manera:

open(PASSWD, "/etc/passwd");
while ($p = <PASSWD>) { # lee una línea del archivo
    chop($p); #quitamos el salto de línea
    @field = split(/:/, $p);
    print " Usuario $field[0] y su directorio es $field[5]";
}
close(PASSWD);

A continuación se da de alta a un usuario si clave de paso, esto se realiza escribiendo en el archivo "/etc/passwd":

open(PASS, ">>/etc/passwd");
print PASS, "$login::$uid:$gid:$information:";
print PASS, "$login_dir:$login_shell\n";
close(PASS);

Si STDIN se encuentra del operador <>, lee una línea cada vez desde ese manejador de archivo. Por ejemplo:

$uno = <STDIN>;
$dos =<STDIN>;
print $uno.$dos;

Al ejecutar este script, teclear unas palabras seguidas de enter y repetir lo mismo una segunda vez. A medida que escribimos <STDIN> lee lo que tecleamos y al pulsar enter lo asigna a la variable $uno. Lo mismo ocurre le ocurre a $dos. Pero, si se ejecuta este otro script:

while ($linea = <STDIN>) {
   print $linea;
}

Este script permite hacer un bucle para leer y escribir tantas líneas como queramos. La condición se escribe entre paréntensis y las líneas que hacen el bucle entre llaves. Para finalizar la entradadesde el teclado pulsar Control+Z.

Por otro lado, el acceso en lectura a un archivo es dependiente del contexto. En un contexto escalar, Perl lee un archivo línea por línea y lo asigna al escalar. En un contexto de array o lista, el acceso al contenido del archivo entraña una lectura completa del archivo. Cada elemento del archivo contiene entonces una línea completa del archivo leído. Por ejemplo:

$file = "datos.txt";
open(DATA, $file) || die "no se puede abrir el archivo\n";
@lineas = <DATA>   # lee todo el archivo.
close(DATA);
La función die manda una cadena de caracteres por el canal de error.

Esta propiedad debe utilizarse con precaución, porque la lectura completa de un archivo corre el riesgo de ser muy costosa en memoria. Por otra parte, el lenguaje Perl utiliza caches para las entradas/salidas y en consecuencia la lectura completa de un archivo no entraña necesariamente una ganancia en materia de rendiemiento.

3. Los canales de comunicación (pipes).

La rutina open de Perl puede utilizarse tambiém para ejecutar mandatos del shell, modificar sus entradas y recuperar sus salidas. Cuando el nombre del archivo lleva como prefijo el carácter |, este nombre se trata como un mandato. Este mandato se ejecuta y comunica con el script Perl mediante la rutina print. Veamos un ejemplo:

open(MAIL, "Mail root"); # prepara un mail al superusuario
# contenido del mail
print MAIL "La cuenta del usuario a2344 ha expedido";
# envío del mail
close(MAIL);

Por otro lado, cuando el nombre del archivo va seguido del carácter |, el mandato se ejecuta y se puede acceder a su resultado por medio del operador <>. Por ejemplo:

# examina las personas conectadas a la máquina
open(WHO, "who|");
while($who = <WHO>) {
   chop $who; # suprime el retorno de carro
   ($user, $tty, $junk) = split(/\s+/, $who, 3);
   print "El usuario $user está en la terminal $tty\n";
}
close(WHO);

4. Los operadores de comprobación de archivos.

Estos operadores tratan de resolvernos diferentes problemas como la verificación de la existencia de un archivo antes de modificarlo o la supresión de archivos existentes en la creación de archivos con el mismo nombre. Estas verificaciones se llevan a cabo mediante operadores que proporcionan información relativa a los archivos. Estos opeadores que veremos en la tabla que se muestra a continuación son unarios, su argumento es un puntero de archivo.

operadores de comprobación de archivos

Por ejemplo:

$data = "data.txt";
if (e- $data) {
   # OK, el archivo existe
   open ...
}
else {
   print "el archivo $data no existe.\n";
}

5. Las funciones print, printf  y sprintf.

Las funciones print y printf permiten la escritura o la visualización de un resultado. El operador print envía la cadena de caracteres al puntero de archivo pasado como argumento. Cuando éste está ausente, el utilizado es el puntero STDOUT que representa la salida estándar (la consola). La sintaxis de este operador es:

print PUNTERO $str1, $str1, ..., $strN;

Por otro lado la función printf permite especificar el formato de escritura. El texto así formateado se envía al puntero de archivo pasado como argumento. Este formato es idéntico al del lenguaje C. Por lo tanto el texto formateado consta de una ristra de caracteres. Los caracteres de ristra se escriben tal cual a excepción del %. El % indica que hay que mostrar un parámetro de la lista, el siguiente al último mostrado, con un formato en concreto el cual lo indica el caracter que sigue al %. Los caracteres más comunes y el tipo de datos que representa se muestra en la siguiente tabla:

Caracteres de formato

Si se desea imprimir el % como un carácter dentro de una cadena de control, debe utilizarse %%.

Hay que tener en cuenta que los literales de ristras permiten escribir caracteres especiales con lo que se denomina un secuencia de escape. La secuencia de escape comienza siempre con "\" y a continuación se escribe otro carácter que representa el código especial o el número en octal o hexadecimal de su código ASCII. Las secuencias de escape representan un único carácter en la ristra donde aparecen.

Caracteres especiales

Un ejemplo sencillo:

printf PUNTERO "%s %f", $string, $float;
printf "Enteros: base10=%s, base8=%o, base16=%x\n", $y, $z, $w;
# El identificador es STDOUT (visualización por pantalla).

La función sprintf devuelve una cadena de caracteres formateada por la conveciones normalmente utilizadas por printf, para ello se recomienda ver las dos tablas anteriores. Para ver mejor el funcionamiento de esta rutina introducimos el siguiente ejemplo:

$lenguaje = "Perl";
$longitud = 10;
$conformato = sprintf("%s", $lenguaje);
print $conformato,"\n";                      # Imprime:Perl
$conformato = sprintf(">>%s<<", $lenguaje);
print $conformato,"\n";                      # Imprine:>>Perl<<
$conformato = sprintf(">>%s <<", $lenguaje);
print $conformato,"\n";                      # Imprime:>>Perl <<
$conformato = sprintf(">>%10s<<", $lenguaje);
print $conformato,"\n";                      # Imprime:>> Perl<<
$conformato = sprintf(">>%-10s<<", $lenguaje);
print $conformato,"\n";                      # Imprime:>>Perl <<
$conformato = sprintf(">>%-${longitud}s<<", $lenguaje);
print $conformato,"\n";                      # Imprime:>>Perl <<

6. Las funciones para manejo de ficheros.

Para realizar un mejor tratamiento de los datos que se encuentran en ficheros, Perl posee una serie de funciones predefinidas que nos ayudan a realizar esta tarea con gran facilidad y simpleza. A continuación mencionaremos a las funciones más usadas por todos los programadores de Perl.

  • read(manejador, variable, longitud, [desplazamiento]). Esta función lee desde un fichero, especificado en el parámetro manejador, un número de bytes, especificado por el parámetro longitud, y lo introduce en una variable de tipo escalar representada por el parámetro variable. El parámetro desplazamiento, si se especifica, indica desde que posición del fichero se empieza a leer. Por defecto, es la posición donde se encuentra el puntero. He aquí algunos ejemplos:
open(DAT,"<datos.txt");
read(DAT, $var, 30);
# $var tiene los primeros 30 caracteres de
# datos.txt
  • seek(manejador, posición, referencia). La función seek pone el puntero del fichero especificado por el parámetro manejador en el lugar indicado por el parámetro posición. El parámetro posición puede tener un valor positivo que nos indica un desplazamiento hacia el final del fichero o un valor negativo que nos indica un deplazamiento hacia el inicio del fichero. Este desplazamiento indicado en el parámetro posición se puede hacer desde el principio del fichero, desde la posición del puntero actual del fichero o desde el final del fichero. Esto lo determina el parámetro referencia con los valores 0,1 y 2 respectivamente. Ejemplo:
open(DAT,"<datos.txt");
read(DAT, $var, 30);
seek(DAT,-31,1);
read(DAT, $var, 30); # Volvemos a leer lo mismo.
  • tell(manejador). Esta función retorna la posición del puntero en el fichero especificado en el parámetro manejador. Ejemplo:

open(DAT,"<datos.txt");
read(DAT, $var, 30);
$ptr = tell(DAT);    # $ptr = 31;

  • eof(manejador). Esta función retorna 1 (verdadero) si el fichero especificado por el parámetro manejador tiene el puntero en el final del mismo. Tambiém devolverá uno si el manejador no está asociado a ningún fichero. En el ejemplo que viene a continuación se leerá un fichero de nombre en el que cada uno de ellos está en una línea del fichero y ocupa 50 caracteres contando con el de salto de línea.
open(NOM,"<nombres.txt);
while (!(eof(NOM))) {
    read(NOM, $nombre, 50);
    print $nombre;
}
Índice Entrada/Salida Variables predefinidas Creación de funciones