• Publicidad

La inteligencia artificial ya sabe programar bien en Perl

¿Tienes algo interesante que decir? ¿O quizá algo no tan interesante? Aquí tenemos un espacio para compartir todo lo que queramos decir y que no cabe en ninguno de los otros foros.

La inteligencia artificial ya sabe programar bien en Perl

Notapor explorer » 2024-09-18 01:42 @112

... o casi.

Hace unos años hice algunas pruebas con ChatGPT y el resultado era horrible. En cuanto solicitabas la elaboración de un script medianamente complicado, se empezaba a inventar cosas.

Al año siguiente repetí la prueba y bueno, salían cosas muy interesantes. Tenías que repasar el código, desde luego, pero ya había avanzado mucho. Cierto es que seguía inventándose líneas, bibliotecas y código extraño. Pero se lo decías, te pedía perdón y lo volvía a intentar. Seguro que insistiendo saldría lo pedido.

Hace unos minutos he pedido la realización de un script medianamente complejo. Le he explicado todos los pasos con detalle. Y ChatGPT (el modelo gratuito) me ha generado un script de 100 líneas, de las cuales sólo una "sobra". Sorprendente.

Dejo aquí para la posteridad semejante logro. Después del código pongo algún comentario al respecto.

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Necesito un script en lenguaje Perl, que analice todos los archivos *.conf del directorio /etc/awffull.
Por cada archivo, lo abrimos y buscamos por una línea que comience por la palabra LogFile.
A continuación de esa palabra (separada de la anterior por uno o más espacios), hay una ruta a un archivo de tipo log. Esa ruta tiene este aspecto: "/var/log/apache2/DOMINIO-access.log.1" siendo DOMINIO lo que va a variar dentro del bucle principal.
Hay que tomar esa ruta, quitarle la última parte ".1".
Entonces, en el directorio /var/log/apache2/ buscamos por todos los archivos cuyo nombre vaya desde DOMINIO-access.log.52.gz hasta DOMINIO-access.log.2.gz (o sea, vamos decrementando desde 52 a 2).
Por cada archivo encontrado, lo abrimos y leemos (necesitaremos una biblioteca para leer archivos gzip).
Sólo nos interesa saber si alguna líneas del archivo contiene el texto "GET /Estadisticas/ ".
Hacemos lo mismo con los archivos DOMINIO-access.log.1 y DOMINIO-access.log
Si en todos estos archivos, no apareció el texto buscado, debemos desactivar el archivo .conf leído antes. Para ello, lo renombramos añadiendo al nombre anterior el sufijo '.off'.
Repetimos para los demás archivos.
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Resultado:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use File::Grep qw(fgrep);
  5. use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
  6. use File::Copy;
  7.  
  8. # Directorio de configuración y logs
  9. my $conf_dir = "/etc/awffull";
  10. my $log_dir = "/var/log/apache2";
  11.  
  12. # Abrimos el directorio /etc/awffull
  13. opendir(my $dh, $conf_dir) or die "No se puede abrir el directorio $conf_dir: $!";
  14.  
  15. # Recorremos cada archivo *.conf
  16. while (my $conf_file = readdir($dh)) {
  17.     next unless $conf_file =~ /\.conf$/;  # Solo procesamos archivos .conf
  18.  
  19.     my $conf_path = "$conf_dir/$conf_file";
  20.  
  21.     # Abrimos el archivo .conf
  22.     open(my $fh, '<', $conf_path) or die "No se puede abrir $conf_path: $!";
  23.  
  24.     # Buscamos la línea que comienza con "LogFile"
  25.     my $log_file;
  26.     while (my $line = <$fh>) {
  27.         if ($line =~ /^LogFile\s+(.+)$/) {
  28.             $log_file = $1;  # Capturamos la ruta del archivo log
  29.             last;
  30.         }
  31.     }
  32.     close($fh);
  33.  
  34.     # Si no encontramos una línea con "LogFile", pasamos al siguiente archivo
  35.     next unless defined $log_file;
  36.  
  37.     # Quitamos la extensión ".1" al archivo de log
  38.     $log_file =~ s/\.1$//;
  39.  
  40.     # Extraemos el nombre del dominio
  41.     my ($dominio) = $log_file =~ /\/var\/log\/apache2\/(.+)-access\.log/;
  42.  
  43.     # Si no podemos extraer el dominio, pasamos al siguiente archivo
  44.     next unless defined $dominio;
  45.  
  46.     my $found = 0;
  47.  
  48.     # Función para verificar si el archivo contiene "GET /Estadisticas/"
  49.     sub contains_estadisticas {
  50.         my ($file) = @_;
  51.         if ($file =~ /\.gz$/) {
  52.             my $input = IO::Uncompress::Gunzip->new($file) or die "No se puede abrir $file: $GunzipError";
  53.             while (my $line = <$input>) {
  54.                 return 1 if $line =~ /GET \/Estadisticas\//;
  55.             }
  56.         } else {
  57.             open(my $log_fh, '<', $file) or die "No se puede abrir $file: $!";
  58.             while (my $line = <$log_fh>) {
  59.                 return 1 if $line =~ /GET \/Estadisticas\//;
  60.             }
  61.             close($log_fh);
  62.         }
  63.         return 0;
  64.     }
  65.  
  66.     # Verificamos los archivos DOMINIO-access.log.52.gz a DOMINIO-access.log.2.gz
  67.     for (my $i = 52; $i >= 2; $i--) {
  68.         my $gz_file = "$log_dir/$dominio-access.log.$i.gz";
  69.         if (-e $gz_file) {
  70.             if (contains_estadisticas($gz_file)) {
  71.                 $found = 1;
  72.                 last;
  73.             }
  74.         }
  75.     }
  76.  
  77.     # Verificamos DOMINIO-access.log.1 y DOMINIO-access.log
  78.     if (!$found && -e "$log_file.1" && contains_estadisticas("$log_file.1")) {
  79.         $found = 1;
  80.     }
  81.  
  82.     if (!$found && -e "$log_file" && contains_estadisticas($log_file)) {
  83.         $found = 1;
  84.     }
  85.  
  86.     # Si no encontramos "GET /Estadisticas/", desactivamos el archivo .conf
  87.     if (!$found) {
  88.         my $new_conf_file = "$conf_file.off";
  89.         rename($conf_path, "$conf_dir/$new_conf_file") or warn "No se puede renombrar $conf_path a $new_conf_file: $!";
  90.         print "Desactivado: $conf_file\n";
  91.     }
  92. }
  93.  
  94. closedir($dh);
  95.  
Coloreado en 0.005 segundos, usando GeSHi 1.0.8.4

El código es completamente funcional. Sí: funciona y además hace lo que se le pide.

Pero... hay algunas cosillas que comentar.
  • La línea 4 -use File::Grep qw(fgrep);- sobra. De hecho, este es el único "fallo". Pero es un fallo mínimo. Simplemente, no usa el método 'fgrep' en el resto del programa.
  • Hay mucho código que se puede simplificar. Por ejemplo, aunque es un acierto crear una subrutina para detectar la presencia de la cadena "GET /Estadisticas/", el procesamiento de los archivos en formato gzip es prácticamente idéntico a la de los archivos no comprimidos, así que en vez de tener un bucle y un par de pruebas más abajo, se puede hacer todo en un único bucle.
Esta es mi versión, que no difiere mucho.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. #
  3. # Desactiva archivos de configuración en el Awffull (generador informes actividad web).
  4. #
  5. # Debido a que los clientes no suelen ver estas estadísticas, lo mejor es desactivarlas
  6. # cuando ha pasado un tiempo prudencial (un año en este código).
  7. # La desactivación se hace agregando '.off' al nombre del archivo de configuración.
  8. #
  9. # [Entrada]
  10. #   Ninguna
  11. #
  12. # [Salida]
  13. #   Ninguna
  14. #
  15. # Joaquín Ferrero, 20240917, basada en la solución propuesta por ChatGPT
  16. # Última versión:  20240917
  17. #
  18. use v5.24.1;
  19. use Path::Tiny;
  20. use IO::Uncompress::Gunzip;
  21.  
  22. ### Configuración ###
  23. my $conf_dir = path('/etc/awffull');
  24. my $logs_dir = path('/var/log/apache2');
  25.  
  26. ### Procesamiento de los archivos de configuración ###
  27. foreach my $conf_file ($conf_dir->children( qr/\.conf$/ )) {
  28.  
  29.     # Nombre del archivo de registro (log)
  30.     my $log_file;
  31.     for ($conf_file->lines({ count => 50 })) {
  32.         if (/^LogFile\s+(.+?)(\.1)?$/) {
  33.             $log_file = $1;                     # Capturamos la ruta del archivo log
  34.             last;
  35.         }
  36.     }
  37.     next unless defined $log_file;
  38.  
  39.     # Nombres de los archivos a analizar:
  40.     # log_file
  41.     # log_file.1
  42.     # log_file.2.gz
  43.     # ...
  44.     # log_file.52.gz
  45.     my @logs = ((map { "$log_file$_" } "", ".1"), (map { "$log_file.$_.gz" } 2..52));
  46.  
  47.     # Buscar llamada a Estadisticas, en los archivos pasados y presente
  48.     my $encontrado = 0;
  49.  
  50.     for my $log (@logs) {
  51.         next if not -e $log;
  52.  
  53.         # Abrir archivo, comprimido o no
  54.         my $fh = $log =~ /\.gz$/
  55.                ? (IO::Uncompress::Gunzip->new($log) or die "gunzip failed: $!")
  56.                : path($log)->filehandle("<")
  57.                ;
  58.  
  59.         while (<$fh>) {
  60.             if (m{GET /Estadisticas\/? }) {
  61.                 $encontrado = 1;                # Se encontró
  62.                 last;
  63.             }
  64.         }
  65.  
  66.         close $fh;
  67.  
  68.         last if $encontrado;                    # No es necesario buscar más
  69.     }
  70.  
  71.     if (not $encontrado) {
  72.         say "$conf_file -> $conf_file.off";
  73.         $conf_file->move("$conf_file.off");
  74.     }
  75. }
  76.  
  77. __END__
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Publicidad

Volver a Pasando el rato

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado