• Publicidad

Ayuda con Script

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Ayuda con Script

Notapor maschino » 2008-06-16 06:15 @302

Buenos días.

Llevo tiempo peleándome con Perl (estoy aprendiendo) y me estoy haciendo un script que me falla, pero no veo dónde. ¿Me podéis echar una mano? Me imagino que para vosotros sea una tontería, pero yo me estoy volviendo tonto (más).

Tengo un fichero que está dividido en columnas separadas por un tabulador. Solo busco el separar las líneas internas del fichero en 3 ficheros de texto para después tratarlo con Excel.

A ver si alguno me dice porqué me da error (Ya sé que tendré mil errores y que se puede hacer mucho mejor, pero para ser "mi primera vez" tampoco creo que este tan mal...

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
## EJECUTA UNA CONSULTA AL BPERROR PARA SACAR LOS ERRORES
$ejecucion=`bperror -U -backstat -s info -d 04/14/08 -e 04/14/08`;

## LO VOLCAMOS A UN FICHERO AUXILIAR PARA LEERLO
## PARA ESO PRIMERO LO TENEMOS QUE GENERAR Y ABRIR
open (AUXILIAR,">C:/auxiliar.txt");

## DESPUES LE VOLCAMOS LOS DATOS DE LA VARIABLE
print AUXILIAR $ejecucion;

## LO CERRAMOS PARA GUARDARLO
close (AUXILIAR);

## LO LEEMOS Y RECORREMOS PARA METER EN UNA ARRAY LAS LINEAS CON ERROR 0 Y 1
## LAS EXPLICACIONES DE LOS ERRORES LAS OBVIAMOS
## LOS ERRORES DISTINTOS DE 0 Y 1 LOS METEMOS EN OTRO FICHERO
## CONTABILIZAMOS TODO

## SE INICIALIZAN LAS VARIABLES
$totales=0;
$errores_0_1=0;
$errores_196=0;
$todo_errores=0;

## LO ABRIMOS PARA LEERLO DE NUEVO

open (AUXILIAR,"C:/auxiliar.txt");

## AÑADIMOS CADA LINEA A UNA MATRIZ

@registros=<AUXILIAR>;

## LO RECORREMOS BUSCANDO EN LA CADENA DEL PRINCIPIO
## TODO LO DISTINTO A "(" LO CONTAMOS EN LA VARIABLE TOTALES

foreach <>\( (@registros);
$totales=$totales+1;
 
## TODO LOS ERRORES A 196 LO CONTAMOS Y LO METEMOS EN OTRO FICHERO
## Y COMO SON ERRORES TAMBIEN SE CONTABILIZA EN TODOS_ERRORES
 if ($registros =~/^196)/)
 {
 $errores_196 = $errores_196 + 1;
 $todo_errores = todo_errores + 1;
 open (fichero_196, ">C:/errores_196.txt");
 print fichero_196 $registros;
 }
## TODOS LOS ERRORES DISTINTOS A "0" O "1" SE MANDAN A OTRO FICHERO
        else if (($registros =~/^  0/)||($registros =~/^  1/))
        {
        open (fichero_dist_0, ">>C:/errores_0_y_1.txt");
        print fichero_dist_0 $registros;
        }

## EL RESTO DE LOS ERRORES LOS VOLCAMOS A OTRO FICHERO Y LOS CONTAMOS
open (fichero_dist_0, ">C:/errores.txt");
print fichero_dist_0 @registros;
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Muchas gracias de antemano...
maschino
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2008-06-16 06:08 @297

Publicidad

Notapor explorer » 2008-06-16 10:54 @496

Bienvenido a los foros de Perl en Español, maschino.

Sí que veo algunas cosas que no entiendo:
* Está línea está mal:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
 foreach <>\( (@registros);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Yo supongo que habrás querido decir
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
foreach ( @registros ) {
    $totales++ if ! /^\(/;
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

*
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
@registros=<AUXILIAR>;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
no guarda una línea cada vez, sino TODAS las líneas de AUXILIAR
* ¿De dónde sale la variable $registros a la mitad del programa?
* ¿Qué es lo que hace la función todo_errores?


Te aconsejo lo siguiente. Cuando uno está aprendiendo Perl, es muy recomendable poner
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
use warnings;
use strict;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
al principio del programa. Con el primero, Perl nos avisará de los posibles errores que vaya encontrando. El segundo, nos obligará a programar de forma estricta.

Puede parecer un rollo tener que definir todas las variables (por ejemplo, para crear una variable pondríamos my $registros; al principio), pero así nos aseguramos de que no cometemos errores ortográficos (escribimos el nombre de una variable distinto de la que le correspondería).

No está muy claro cómo haces la división del fichero, por lo que no puedo darte más pistas, hasta que no me des las tuyas.
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

Notapor maschino » 2008-06-17 02:56 @164

Muchas gracias por contestar. Perdona por no haber dado más pistas de cómo es la construcción del fichero....

Te comento, realmente lo único que hago es exportar una salida de un programa a un fichero. Esa salida es un documento de texto dividido en columnas, y lo que busco es separar las distintas líneas dependiendo del inicio de la línea a 3 ficheros distintos.

Como habrás podido notar, aun no llego a categoría de novato... :oops:

El formato del fichero sería algo así:
Código: Seleccionar todo
196    PPTCB01    VMWARE_DTIW2K3_A FULL_SEMAN unknown     06/16/2008 00:04:39
                 (client backup was not attempted because backup window closed)
196    PPTCB01    VMWARE_PPT2K3_C FULL_SEMAN unknown     06/16/2008 00:04:39
                 (client backup was not attempted because backup window closed)
196    PPTCB01    VMWARE_PPT2K3_A FULL_SEMAN unknown     06/16/2008 00:04:40
                 (client backup was not attempted because backup window closed)
  2    PPTCONBCK1     BACKUP_CATALOG_O Full       unknown     06/16/2008 00:04:40
                 (none of the requested files were backed up)
  0    FSPPTSQL1        FSSQL1_SQLSERVER Default-Ap PPTconbck1   06/16/2008 00:05:09
  0    AGGISPPT         AGGIPPTS_SQLSERVER_ Default-Ap PPTconbck1   06/16/2008 00:05:15
  0    FCCPPTVS01  FCCPPTVS01_SQL Default-Ap fsconbck1   06/16/2008 00:05:35
  0    FCPPTITPPMP01   SISTEMAS_SERVERS Default-Ap PPTconbck1   06/16/2008 00:05:38
  0    FCITPPMPPPT01   SISTEMAS_SERVERS Default-Ap PPTconbck1   06/16/2008 00:05:39

Y la única intención es que lo separe en 3 ficheros distintos. Uno para los que empiecen en 0 ó 1, otro para los que empiecen por 196 y otro para el resto, eliminando las líneas que no empiecen por ninguno de estos...
Ej.: (none of the requested files were backed up)

Se que sera una tontería el conseguir hacer esto, y se hará con 3 líneas, pero de momento no consigo mucho...

Muchas gracias por tu ayuda.
maschino
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2008-06-16 06:08 @297

Notapor explorer » 2008-06-17 05:20 @263

Pues sí, se puede hacer fácil, pero no ibas desencaminado.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use warnings;
use strict;

my @consulta = qx(bperror -U -backstat -s info -d 04/14/08 -e 04/14/08);

my $totales;
my $errores_196;
my $errores_0_1;
my $errores;

open (LINEAS196, ">errores_196.txt"  );
open (LINEAS0Y1, ">errores_0_y_1.txt");
open (LINEASNO0, ">errores.txt"      );

foreach my $linea ( @consulta ) {
    $totales++;

    my ($comienzo) = $linea =~ /^\s*(\d+)/;      # Nos quedamos con el primer número de la línea

    if ( not defined $comienzo ) {
        $errores++;
        print LINEASNO0 $linea;
    }
    elsif ( $comienzo == 196 ) {
        $errores_196++;
        print LINEAS196 $linea;
    }
    elsif ( $comienzo == 0 or $comienzo == 1 ) {
        $errores_0_1++;
        print LINEAS0Y1 $linea;
    }
    else {
        $errores++;
        print LINEASNO0 $linea;
    }
}

close LINEAS196;
close LINEAS0Y1;
close LINEASNO0;

print "Totales: $totales\n";
print "Líneas 196: $errores_196\n";
print "Líneas 0y1: $errores_0_1\n";
print "Líneas no0: $errores\n";

__END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Código: Seleccionar todo
explorer@joaquin:~/Documents/Desarrollo> ./kk.pl
Totales: 13
Líneas 196: 3
Líneas 0y1: 5
Líneas no0: 5
explorer@joaquin:~/Documents/Desarrollo> cat errores.txt
                 (client backup was not attempted because backup window closed)
                 (client backup was not attempted because backup window closed)
                 (client backup was not attempted because backup window closed)
  2    PPTCONBCK1     BACKUP_CATALOG_O Full       unknown     06/16/2008 00:04:40
                 (none of the requested files were backed up)
explorer@joaquin:~/Documents/Desarrollo> cat errores_196.txt
196    PPTCB01    VMWARE_DTIW2K3_A FULL_SEMAN unknown     06/16/2008 00:04:39
196    PPTCB01    VMWARE_PPT2K3_C FULL_SEMAN unknown     06/16/2008 00:04:39
196    PPTCB01    VMWARE_PPT2K3_A FULL_SEMAN unknown     06/16/2008 00:04:40
explorer@joaquin:~/Documents/Desarrollo> cat errores_0_y_1.txt
  0    FSPPTSQL1        FSSQL1_SQLSERVER Default-Ap PPTconbck1   06/16/2008 00:05:09
  0    AGGISPPT         AGGIPPTS_SQLSERVER_ Default-Ap PPTconbck1   06/16/2008 00:05:15
  0    FCCPPTVS01  FCCPPTVS01_SQL Default-Ap fsconbck1   06/16/2008 00:05:35
  0    FCPPTITPPMP01   SISTEMAS_SERVERS Default-Ap PPTconbck1   06/16/2008 00:05:38
  0    FCITPPMPPPT01   SISTEMAS_SERVERS Default-Ap PPTconbck1   06/16/2008 00:05:39

Quizás las partes más complicadas sean las de obtener la salida del comando separada en líneas, y la obtención del primer campo de la línea.

En cuanto a lo primero, resulta que es un efecto añadido del uso de qx() (o ``) cuando el resultado se tiene guardar en un array (lo ejecutamos en contexto lista). Al hacerlo de esta manera, cada línea se almacena en un elemento del array, lo mismo que si lo hubiéramos leído línea a línea de un fichero. Así nos ahorramos la creación del fichero temporal.

En cuanto a lo segundo, aplicamos una expresión regular para buscar el primer campo. Lo que hace es buscar un número

Se puede hacer de otra manera, usando $comienzo = substr($linea,0,3); con lo que obtenemos los 3 primeros caracteres de la línea. Luego solo hay que hacer comparaciones de caracteres:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
    if ( $comienzo eq '196' ) {
    if ( $comienzo eq '  0' ) {
    if ( $comienzo eq '   ' ) {  # para las líneas de los paréntesis
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

aunque esto solo es válido si es verdad que los primeros caracteres son espacios en blanco, y no tabuladores, por ejemplo.

Como te habrás fijado, hay dos lugares donde repetimos las acciones: cuando no está definido $comienzo (caso de las líneas con paréntesis) y cuando es distinto de 196, 0 y 1 (el resto de las líneas). Bueno, esto tiene la desventaja de que puede dar problemas en el futuro si hacemos algún cambio y se nos olvida actualizar en los dos sitios. Lo ideal es que esté en uno solo sitio.

Para resolverlo, podríamos reescribir el bucle central como:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
foreach my $linea ( @consulta ) {
    $totales++;

    if ( my ($comienzo) = $linea =~ /^\s*(\d+)/ ) {

        if ( $comienzo == 196 ) {
            $errores_196++;
            print LINEAS196 $linea;
            next;
        }
        elsif ( $comienzo == 0 or $comienzo == 1 ) {
            $errores_0_1++;
            print LINEAS0Y1 $linea;
            next;
        }
    }

    $errores++;
    print LINEASNO0 $linea;
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Aquí, el primer if comprueba si tenemos o no un número en la primera columna. Si es así, comprueba cuál es, actúa y luego continúa con la siguiente (next) línea. Si no coincide con las que buscamos, continuará hasta el final, lo mismo que si ni hubiese un comienzo, por lo que esos dos casos se contemplan en las últimas líneas del bucle.

Hay más formas de hacerlo, claro...
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

Notapor maschino » 2008-06-17 07:59 @374

Muchas gracias.

Lo acabo de probar y funciona más que muy correctamente. Mi idea era lo que has hecho tu, pero sin saber (es lo que tiene el desconocimiento).

Otra pregunta estúpida: en el que hice yo, en los condicionales, yo trataba los que no tenían números al principio como basura, ¿se podría hacer lo mismo con tus condicionales?

Buscando por ejemplo por el carácter "(". Lo digo porque si busco vacío, también me pondría como error los <espacio><espacio>0 por ejemplo, ¿no?

¿O quizá sea mejor buscar que en los 3 primeros caracteres no sean numéricos, no?
maschino
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2008-06-16 06:08 @297

Notapor explorer » 2008-06-17 08:16 @386

Sí, hay varias formas de hacerlo.

En la expresión regular estoy buscando números, pero si se trata de la línea con errores, entonces la expresión regular me deja la variable $comienzo a indefinido, por lo que este caso lo trato en el if ( not defined $comienzo ) {.

Otra forma es mirar los 3 primeros caracteres. Puedes hacer algo muy básico que es extraerlos con substr() y luego hacer comparaciones. Esto está explicado en la segunda parte de mi anterior respuesta.

Puedes hacer también lo que comentas: mirar que esos tres primeros caracteres no sean numéricos:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$comienzo = substr $linea, 0, 3;
if ( $comienzo =~ /^ *\d+$/ ) { # hay un número con una posible serie de espacios delante
Coloreado en 0.001 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

Notapor maschino » 2008-06-17 08:41 @403

Lo conseguí antes de leerte buscando con otro elsif en la ultima opción que fuese mayor o igual a 0 (antes de que lo metiese en errores). Como ya estaban filtrados los valores más interesantes para mi, solo me quedaba una compara cion cualquiera numérica (hice >=0).

Muchas gracias, la verdad es que me has hecho el script de cabo a rabo al final.

:lol:

Me seguiré pasando por aquí, a ver si aprendo algo más, porque sino... :roll:
maschino
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2008-06-16 06:08 @297

Notapor explorer » 2008-06-17 10:19 @471

Lo más importante es que hayas entendido el funcionamiento. Y lo importante que son las expresiones regulares, uno de los cuatro pilares de Perl.
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


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 5 invitados