Programación en Perl
      Input / Output
Entrada estándar

Se utiliza el operador <STDIN>

  Si se usa en contexto escalar lee una línea

  Si se usa en contexto de lista, lee hasta que
  se detecta un EOF (CTRL-D Unix o CTRL-Z en
  windows)

Este operador devuelve undef cuando se detecta
el fin de línea
Entrada estándar

        Gracias a que devuelve undef podemos escribir
        el siguiente código

while (defined($line = <STDIN>)) {
    print "I saw $line";
}
Entrada estándar

        Esta última construcción es tan habitual que
        existe una forma de escribirla mucho más
        compacta.


while (<STDIN>) {
    say "Línea: $_";
}
Entrada estándar
Entrada estándar

Esta notación más compacta funciona sólo si se
usa de esta forma.
Entrada estándar

Esta notación más compacta funciona sólo si se
usa de esta forma.

Si se utiliza el operador <STDIN> en algún otro
lugar, la línea no se carga en la variable $_
Entrada estándar

           Esta notación más compacta funciona sólo si se
           usa de esta forma.

           Si se utiliza el operador <STDIN> en algún otro
           lugar, la línea no se carga en la variable $_


#ESTO DA UN ERROR: no se lee la línea en la variable $_
<STDIN>;
say "$_";
Entrada estándar

           Como ya hemos visto, el operador <STDIN> en
           contexto de lista devuelve todas las líneas que
           faltan y las guarda en un array.

           ¿Qué diferencia hay entre while(<STDIN>) de
           los ejemplos anteriores y el siguiente:

foreach(<STDIN>) {
    chomp;
    say;
}
El operador <>
El operador <>

Sirve para facilitarnos la tarea de hacer scripts
que se comporten como programas Unix
El operador <>

Sirve para facilitarnos la tarea de hacer scripts
que se comporten como programas Unix

                               muestra el
cat fich1.txt fich2.txt fich3.txt
contenido de los tres ficheros por pantalla
El operador <>

Sirve para facilitarnos la tarea de hacer scripts
que se comporten como programas Unix

                               muestra el
cat fich1.txt fich2.txt fich3.txt
contenido de los tres ficheros por pantalla

¿Cómo conseguimos lo mismo con nuestro script?
miscript.pl fich1.txt fich2.txt fich3.txt
El operador <>

while (<>) {
    chomp;
    print "Leído: $_n";
}
El operador <>

while (<>) {
    chomp;
    print "Leído: $_n";
}


             miscript.pl fich1.txt fich2.txt fich3.txt
El operador <>

while (<>) {
    chomp;
    print "Leído: $_n";
}


             miscript.pl fich1.txt fich2.txt fich3.txt

             Lee todas las líneas de fich1.txt
El operador <>

while (<>) {
    chomp;
    print "Leído: $_n";
}


             miscript.pl fich1.txt fich2.txt fich3.txt

             Lee todas las líneas de fich1.txt

             Lee todas las líneas de fich2.txt
El operador <>

while (<>) {
    chomp;
    print "Leído: $_n";
}


             miscript.pl fich1.txt fich2.txt fich3.txt

             Lee todas las líneas de fich1.txt

             Lee todas las líneas de fich2.txt

             Lee todas las líneas de fich3.txt
El operador <>

while (<>) {
    chomp;
    print "Leído: $_n";
}


             miscript.pl fich1.txt fich2.txt fich3.txt

             Lee todas las líneas de fich1.txt

             Lee todas las líneas de fich2.txt

             Lee todas las líneas de fich3.txt

             Termina
Argumentos del script

Perl guarda todos los argumentos con los que se
ejecuta un script en el array @ARGV.

@ARGV es un array así que podemos, por
ejemplo, procesarlo con un foreach para ver qué
argumentos empiezan con - y procesarlos
convenientemente.
Salida estándar

Las funciones print y say esperan una lista de
cadenas para imprimir, es decir, evalúa sus
argumentos en un contexto de lista.

¿Qué hacen estos scripts?

  print <>        -> comando   cat


  print sort <>   -> comando   sort
Salida estándar

Las funciones print y say esperan una lista de
cadenas para imprimir, es decir, evalúa sus
argumentos en un contexto de lista.

¿Qué hacen estos scripts?

  print <>        -> comando   cat


  print sort <>   -> comando   sort
Cosas de perl...


¿Qué se imprime por pantalla en cada caso?

  print (3+2)

  print (3+2)*4
Cosas de perl...


¿Qué se imprime por pantalla en cada caso?

  print (3+2)     -> se muestra 5

  print (3+2)*4   -> se muestra 5
Cosas de perl...
Cosas de perl...

En perl los paréntesis son opcionales si su uso
no cambia el significado de una expresión.
Cosas de perl...

En perl los paréntesis son opcionales si su uso
no cambia el significado de una expresión.

Por eso podemos escribir
print sort <> en lugar de print ( sort ( <> ) )
Cosas de perl...

En perl los paréntesis son opcionales si su uso
no cambia el significado de una expresión.

Por eso podemos escribir
print sort <> en lugar de print ( sort ( <> ) )

Si parece una llamada a una función, entonces
se interpreta como una llamada a una función
Cosas de perl...

En perl los paréntesis son opcionales si su uso
no cambia el significado de una expresión.

Por eso podemos escribir
print sort <> en lugar de print ( sort ( <> ) )

Si parece una llamada a una función, entonces
se interpreta como una llamada a una función

¿Y esto en castellano qué quiere decir?
Abrir un fichero

open CONFIG, '/etc/my.cnf';
open CONFIG, '</etc/my.cnf';
open DATOS, '>usuarios.txt';
open LOG, '>>logfile';
Abrir un fichero

        Se puede utilizar cualquier valor escalar para
        indicar el nombre del fichero




$logFile = “/var/log/my.log”
open LOG, “>>$logFile”;
Abrir un fichero
        A partir de perl 5.6 se pueden utilizar tres
        argumentos

$logFile = “/var/log/my.log”
open LOG, “>>”,$logFile ;


     Ventajas:

        más seguro

        se puede especificar la codificación:
        open LOG, “>>:encoding(utf-8)”,$logFile ;
Abrir un fichero

Más ventajas:

  el modo <:crlf nos permite leer un fichero de
  windows, convirtiendo automáticamente el fin
  de línea al sistema Unix

  el modo >:crlf nos permite escribir un fichero
  con formato Windows de fin de línea
Cerrar un fichero



     close LOG ;
Control de errores

        La función open devuelve verdadero si el
        fichero pudo abrirse y falso en caso contrario

        La variable especial $! almacenará el error que
        el sistema operativo nos devuelve



if ( ! open LOG, '>>', 'logfile' ) {
    die "No se puede crear el fichero logfile: $!";
}
Leer de un fichero

while (<PASSWD>) {
    chomp;
    ...
}




foreach (<PASSWD>) {
    chomp;
    ...
}
Escribir en un fichero



print LOG “2011-07-28: acceso denegado a luisn”;


printf STDERR “No existe la base de datos VENTAS_2008”
Ejercicios



Escribir dos programas, unix2dos y dos2unix,
que convierta los ficheros de unix en fichero de
windows y viceversa.
Cambiando el selector
            por defecto
        Si vamos a trabajar durante unas cuantas líneas
        de código simpre con el mismo manejador, se
        puede hacer un poco tedioso



print LOG “Se han producido los siguiente error:n”;
print LOG “t- Despliegue incorrecto de base de datosn”;
... (15 líneas de código más abajo)
print LOG “----FIN DEL ERRORn”
Cambiando el selector
            por defecto
        Si vamos a trabajar durante unas cuantas líneas
        de código simpre con el mismo manejador, se
        puede hacer un poco tedioso


select LOG;
print “Se han producido los siguiente error:n”;
print “t- Despliegue incorrecto de base de datosn”;
... (15 líneas de código más abajo)
print “----FIN DEL ERRORn”
select STDOUT;
Control de buffering

          Si se fija la variable especial $| a 1 ($|=1), el
          manejador seleccionado escribe al fichero con
          cada operación de escritura

select LOG;
$| = 1;
select STDOUT;
...
print LOG “Esta línea se escribe directamente al fichero sin
pasar por el buffer.”
Redireccionando STDERR


# Enviando mensajes de error a nuestro log
if ( ! open STDERR, ">>/home/yo/miscript_error_log") {
    die "No se pudo abrir el fichero de log: $!";
}
Redireccionando STDERR
 Casi siempre será mejor permitir al usuario que
 haga la redirección utilizando la shell.

 Situaciones en las que esto puede ser útil:

    Nuestro script se lanza a través o otros
    programas (como un servidor web) donde es
    difícil capturar la salida de error.

 Si perl no puede abrir el nuevo STDERR, STDIN o
 STDOUT, siempre usará los manejadores por
 defecto
Almacenar manejadores
       en variables escalares
        A partir de la versión 5.6 de perl, es posible
        almacenar los manejadores en variables
        escalares

open my $log_fh, '<', 'log.txt'
    or die "No se puedo abrir log.txt: $!";
...
while(<$log_fh>) { ... }


print $log_fh “Mensaje de error”;
Almacenar manejadores
       en variables escalares

        Cuidado con la función print y $_



open my $log_fh, '<', 'log.txt'
    or die "No se puedo abrir log.txt: $!";
while(<$log_fh>) {
    print $log_fh;
}
Almacenar manejadores
       en variables escalares

        Cuidado con la función print y $_



open my $log_fh, '<', 'log.txt'
    or die "No se puede abrir log.txt: $!";
while(<$log_fh>) {
    print {$log_fh} $_;
}
Ejercicios

Escribe un programa (tac) que muestre por
pantalla el contenido de los fichero en orden
inverso a como se introducen como argumentos
del programa. El comando tac fich1 fich2 fich3
debe devolver las líneas del fichero fich3 de la
última a la primera, luego las de fich2 de la
ùltima a la primera y por último las de fich1 de
la última al primera.

Perl4 io

  • 1.
    Programación en Perl Input / Output
  • 2.
    Entrada estándar Se utilizael operador <STDIN> Si se usa en contexto escalar lee una línea Si se usa en contexto de lista, lee hasta que se detecta un EOF (CTRL-D Unix o CTRL-Z en windows) Este operador devuelve undef cuando se detecta el fin de línea
  • 3.
    Entrada estándar Gracias a que devuelve undef podemos escribir el siguiente código while (defined($line = <STDIN>)) { print "I saw $line"; }
  • 4.
    Entrada estándar Esta última construcción es tan habitual que existe una forma de escribirla mucho más compacta. while (<STDIN>) { say "Línea: $_"; }
  • 5.
  • 6.
    Entrada estándar Esta notaciónmás compacta funciona sólo si se usa de esta forma.
  • 7.
    Entrada estándar Esta notaciónmás compacta funciona sólo si se usa de esta forma. Si se utiliza el operador <STDIN> en algún otro lugar, la línea no se carga en la variable $_
  • 8.
    Entrada estándar Esta notación más compacta funciona sólo si se usa de esta forma. Si se utiliza el operador <STDIN> en algún otro lugar, la línea no se carga en la variable $_ #ESTO DA UN ERROR: no se lee la línea en la variable $_ <STDIN>; say "$_";
  • 9.
    Entrada estándar Como ya hemos visto, el operador <STDIN> en contexto de lista devuelve todas las líneas que faltan y las guarda en un array. ¿Qué diferencia hay entre while(<STDIN>) de los ejemplos anteriores y el siguiente: foreach(<STDIN>) { chomp; say; }
  • 10.
  • 11.
    El operador <> Sirvepara facilitarnos la tarea de hacer scripts que se comporten como programas Unix
  • 12.
    El operador <> Sirvepara facilitarnos la tarea de hacer scripts que se comporten como programas Unix muestra el cat fich1.txt fich2.txt fich3.txt contenido de los tres ficheros por pantalla
  • 13.
    El operador <> Sirvepara facilitarnos la tarea de hacer scripts que se comporten como programas Unix muestra el cat fich1.txt fich2.txt fich3.txt contenido de los tres ficheros por pantalla ¿Cómo conseguimos lo mismo con nuestro script? miscript.pl fich1.txt fich2.txt fich3.txt
  • 14.
    El operador <> while(<>) { chomp; print "Leído: $_n"; }
  • 15.
    El operador <> while(<>) { chomp; print "Leído: $_n"; } miscript.pl fich1.txt fich2.txt fich3.txt
  • 16.
    El operador <> while(<>) { chomp; print "Leído: $_n"; } miscript.pl fich1.txt fich2.txt fich3.txt Lee todas las líneas de fich1.txt
  • 17.
    El operador <> while(<>) { chomp; print "Leído: $_n"; } miscript.pl fich1.txt fich2.txt fich3.txt Lee todas las líneas de fich1.txt Lee todas las líneas de fich2.txt
  • 18.
    El operador <> while(<>) { chomp; print "Leído: $_n"; } miscript.pl fich1.txt fich2.txt fich3.txt Lee todas las líneas de fich1.txt Lee todas las líneas de fich2.txt Lee todas las líneas de fich3.txt
  • 19.
    El operador <> while(<>) { chomp; print "Leído: $_n"; } miscript.pl fich1.txt fich2.txt fich3.txt Lee todas las líneas de fich1.txt Lee todas las líneas de fich2.txt Lee todas las líneas de fich3.txt Termina
  • 20.
    Argumentos del script Perlguarda todos los argumentos con los que se ejecuta un script en el array @ARGV. @ARGV es un array así que podemos, por ejemplo, procesarlo con un foreach para ver qué argumentos empiezan con - y procesarlos convenientemente.
  • 21.
    Salida estándar Las funcionesprint y say esperan una lista de cadenas para imprimir, es decir, evalúa sus argumentos en un contexto de lista. ¿Qué hacen estos scripts? print <> -> comando cat print sort <> -> comando sort
  • 22.
    Salida estándar Las funcionesprint y say esperan una lista de cadenas para imprimir, es decir, evalúa sus argumentos en un contexto de lista. ¿Qué hacen estos scripts? print <> -> comando cat print sort <> -> comando sort
  • 23.
    Cosas de perl... ¿Quése imprime por pantalla en cada caso? print (3+2) print (3+2)*4
  • 24.
    Cosas de perl... ¿Quése imprime por pantalla en cada caso? print (3+2) -> se muestra 5 print (3+2)*4 -> se muestra 5
  • 25.
  • 26.
    Cosas de perl... Enperl los paréntesis son opcionales si su uso no cambia el significado de una expresión.
  • 27.
    Cosas de perl... Enperl los paréntesis son opcionales si su uso no cambia el significado de una expresión. Por eso podemos escribir print sort <> en lugar de print ( sort ( <> ) )
  • 28.
    Cosas de perl... Enperl los paréntesis son opcionales si su uso no cambia el significado de una expresión. Por eso podemos escribir print sort <> en lugar de print ( sort ( <> ) ) Si parece una llamada a una función, entonces se interpreta como una llamada a una función
  • 29.
    Cosas de perl... Enperl los paréntesis son opcionales si su uso no cambia el significado de una expresión. Por eso podemos escribir print sort <> en lugar de print ( sort ( <> ) ) Si parece una llamada a una función, entonces se interpreta como una llamada a una función ¿Y esto en castellano qué quiere decir?
  • 30.
    Abrir un fichero openCONFIG, '/etc/my.cnf'; open CONFIG, '</etc/my.cnf'; open DATOS, '>usuarios.txt'; open LOG, '>>logfile';
  • 31.
    Abrir un fichero Se puede utilizar cualquier valor escalar para indicar el nombre del fichero $logFile = “/var/log/my.log” open LOG, “>>$logFile”;
  • 32.
    Abrir un fichero A partir de perl 5.6 se pueden utilizar tres argumentos $logFile = “/var/log/my.log” open LOG, “>>”,$logFile ; Ventajas: más seguro se puede especificar la codificación: open LOG, “>>:encoding(utf-8)”,$logFile ;
  • 33.
    Abrir un fichero Másventajas: el modo <:crlf nos permite leer un fichero de windows, convirtiendo automáticamente el fin de línea al sistema Unix el modo >:crlf nos permite escribir un fichero con formato Windows de fin de línea
  • 34.
  • 35.
    Control de errores La función open devuelve verdadero si el fichero pudo abrirse y falso en caso contrario La variable especial $! almacenará el error que el sistema operativo nos devuelve if ( ! open LOG, '>>', 'logfile' ) { die "No se puede crear el fichero logfile: $!"; }
  • 36.
    Leer de unfichero while (<PASSWD>) { chomp; ... } foreach (<PASSWD>) { chomp; ... }
  • 37.
    Escribir en unfichero print LOG “2011-07-28: acceso denegado a luisn”; printf STDERR “No existe la base de datos VENTAS_2008”
  • 38.
    Ejercicios Escribir dos programas,unix2dos y dos2unix, que convierta los ficheros de unix en fichero de windows y viceversa.
  • 39.
    Cambiando el selector por defecto Si vamos a trabajar durante unas cuantas líneas de código simpre con el mismo manejador, se puede hacer un poco tedioso print LOG “Se han producido los siguiente error:n”; print LOG “t- Despliegue incorrecto de base de datosn”; ... (15 líneas de código más abajo) print LOG “----FIN DEL ERRORn”
  • 40.
    Cambiando el selector por defecto Si vamos a trabajar durante unas cuantas líneas de código simpre con el mismo manejador, se puede hacer un poco tedioso select LOG; print “Se han producido los siguiente error:n”; print “t- Despliegue incorrecto de base de datosn”; ... (15 líneas de código más abajo) print “----FIN DEL ERRORn” select STDOUT;
  • 41.
    Control de buffering Si se fija la variable especial $| a 1 ($|=1), el manejador seleccionado escribe al fichero con cada operación de escritura select LOG; $| = 1; select STDOUT; ... print LOG “Esta línea se escribe directamente al fichero sin pasar por el buffer.”
  • 42.
    Redireccionando STDERR # Enviandomensajes de error a nuestro log if ( ! open STDERR, ">>/home/yo/miscript_error_log") { die "No se pudo abrir el fichero de log: $!"; }
  • 43.
    Redireccionando STDERR Casisiempre será mejor permitir al usuario que haga la redirección utilizando la shell. Situaciones en las que esto puede ser útil: Nuestro script se lanza a través o otros programas (como un servidor web) donde es difícil capturar la salida de error. Si perl no puede abrir el nuevo STDERR, STDIN o STDOUT, siempre usará los manejadores por defecto
  • 44.
    Almacenar manejadores en variables escalares A partir de la versión 5.6 de perl, es posible almacenar los manejadores en variables escalares open my $log_fh, '<', 'log.txt' or die "No se puedo abrir log.txt: $!"; ... while(<$log_fh>) { ... } print $log_fh “Mensaje de error”;
  • 45.
    Almacenar manejadores en variables escalares Cuidado con la función print y $_ open my $log_fh, '<', 'log.txt' or die "No se puedo abrir log.txt: $!"; while(<$log_fh>) { print $log_fh; }
  • 46.
    Almacenar manejadores en variables escalares Cuidado con la función print y $_ open my $log_fh, '<', 'log.txt' or die "No se puede abrir log.txt: $!"; while(<$log_fh>) { print {$log_fh} $_; }
  • 47.
    Ejercicios Escribe un programa(tac) que muestre por pantalla el contenido de los fichero en orden inverso a como se introducen como argumentos del programa. El comando tac fich1 fich2 fich3 debe devolver las líneas del fichero fich3 de la última a la primera, luego las de fich2 de la ùltima a la primera y por último las de fich1 de la última al primera.

Notas del editor

  • #2 \n
  • #3 \n
  • #4 \n
  • #5 Explicar que esto es lo mismo que ponerlo as&amp;#xED;:\n\nwhile (defined($_ = &lt;STDIN&gt;)) {\nprint &quot;I saw $_&quot;; \n}\n\n\n
  • #6 Ver uso incorrecto en stdin.pl\n
  • #7 Ver uso incorrecto en stdin.pl\n
  • #8 Ver uso incorrecto en stdin.pl\n
  • #9 While: lee una l&amp;#xED;nea y te lamuestra en pantalla cada vez\nforeach: lee TODAS las l&amp;#xED;neas y cuando has terminado te las imprime\n\nEn while se va leyendo mientras se ejecuta el bucle\nCon foreach el bucle no se ejecuta hasta que terminas de leer.\n
  • #10 \n
  • #11 \n
  • #12 \n
  • #13 fichero: diamond.pl\n\nSi uno de los ficheros no existe, se da un warning y se salta al siguiente.\n\nSe puede contar la historia de porqu&amp;#xE9; se llama: la hija de Larry lo vi&amp;#xF3; y dijo &amp;#x201C;Eso es un diamante, papi&amp;#x201D; y se qued&amp;#xF3; con ese nombre.\n\n\n
  • #14 fichero: diamond.pl\n\nSi uno de los ficheros no existe, se da un warning y se salta al siguiente.\n\nSe puede contar la historia de porqu&amp;#xE9; se llama: la hija de Larry lo vi&amp;#xF3; y dijo &amp;#x201C;Eso es un diamante, papi&amp;#x201D; y se qued&amp;#xF3; con ese nombre.\n\n\n
  • #15 fichero: diamond.pl\n\nSi uno de los ficheros no existe, se da un warning y se salta al siguiente.\n\nSe puede contar la historia de porqu&amp;#xE9; se llama: la hija de Larry lo vi&amp;#xF3; y dijo &amp;#x201C;Eso es un diamante, papi&amp;#x201D; y se qued&amp;#xF3; con ese nombre.\n\n\n
  • #16 fichero: diamond.pl\n\nSi uno de los ficheros no existe, se da un warning y se salta al siguiente.\n\nSe puede contar la historia de porqu&amp;#xE9; se llama: la hija de Larry lo vi&amp;#xF3; y dijo &amp;#x201C;Eso es un diamante, papi&amp;#x201D; y se qued&amp;#xF3; con ese nombre.\n\n\n
  • #17 fichero: diamond.pl\n\nSi uno de los ficheros no existe, se da un warning y se salta al siguiente.\n\nSe puede contar la historia de porqu&amp;#xE9; se llama: la hija de Larry lo vi&amp;#xF3; y dijo &amp;#x201C;Eso es un diamante, papi&amp;#x201D; y se qued&amp;#xF3; con ese nombre.\n\n\n
  • #18 \n
  • #19 \n
  • #20 \n
  • #21 Preguntar qu&amp;#xE9; sale por pantalla en cada caso\n
  • #22 Preguntar qu&amp;#xE9; sale por pantalla en cada caso\n\nejemplo en cosas_de_perl.pl\n
  • #23 Explicar por qu&amp;#xE9; en el caso anterior se imprime 5 en los dos casos.\nprint(3+2) -&gt; como tiene par&amp;#xE9;ntesis, se imprime 3+2 y se devuelve true (que suele ser 1)\nprint(3+2)*4 -&gt; como tiene par&amp;#xE9;ntesis, se imprime 3+2, se devuelve true y se multiplica por 4.\n
  • #24 Explicar por qu&amp;#xE9; en el caso anterior se imprime 5 en los dos casos.\nprint(3+2) -&gt; como tiene par&amp;#xE9;ntesis, se imprime 3+2 y se devuelve true (que suele ser 1)\nprint(3+2)*4 -&gt; como tiene par&amp;#xE9;ntesis, se imprime 3+2, se devuelve true y se multiplica por 4.\n
  • #25 Explicar por qu&amp;#xE9; en el caso anterior se imprime 5 en los dos casos.\nprint(3+2) -&gt; como tiene par&amp;#xE9;ntesis, se imprime 3+2 y se devuelve true (que suele ser 1)\nprint(3+2)*4 -&gt; como tiene par&amp;#xE9;ntesis, se imprime 3+2, se devuelve true y se multiplica por 4.\n
  • #26 Explicar por qu&amp;#xE9; en el caso anterior se imprime 5 en los dos casos.\nprint(3+2) -&gt; como tiene par&amp;#xE9;ntesis, se imprime 3+2 y se devuelve true (que suele ser 1)\nprint(3+2)*4 -&gt; como tiene par&amp;#xE9;ntesis, se imprime 3+2, se devuelve true y se multiplica por 4.\n
  • #27 Los dos primeros son lo mismo\nel tercero abre un fichero y lo machaca si ya existe\nel cuarto lo abre para a&amp;#xF1;adir.\n\n
  • #28 \n
  • #29 m&amp;#xE1;s seguro porque perl no puede confundir los caracteres del modo del fichero con el caracteres que forman parte del nombre del fichero\n\n
  • #30 \n
  • #31 \n
  • #32 Explicar qu&amp;#xE9; hace la funci&amp;#xF3;n die: imprime el error y muestra el mensaje por pantalla y nos concatena el n&amp;#xFA;mero de l&amp;#xED;nea.\n\nSi no queremos escribir esto todo el rato, podemos usar autodie (use autodie)\n
  • #33 \n
  • #34 \n
  • #35 \n
  • #36 \n
  • #37 Es muy mala idea usar select y, al terminarm no volverlo a poner en STDOUT\n
  • #38 \n
  • #39 \n
  • #40 \n
  • #41 \n
  • #42 \n
  • #43 mirar filehandlers.pl\n
  • #44 \n