Lun Jun 16, 2008 5:15 am
|
 |
maschino
Perlero Nuevo

|
Registrado: 16 Jun 2008
Mensajes: 4
|
|
| Ayuda con Script |
|
|
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...
| Perl: | ## 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; |
Muchas gracias de antemano... |
|
|
|

Lun Jun 16, 2008 9:54 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4092
Ubicación: Valladolid, España
|
|
|
|
|
Bienvenido a los foros de Perl en Español, maschino.
Sí que veo algunas cosas que no entiendo:
* Está línea está mal:
| Perl: | foreach <>\( (@registros); |
Yo supongo que habrás querido decir
| Perl: | foreach ( @registros ) {
$totales++ if ! /^\(/;
} |
* | Perl: | @registros=<AUXILIAR>; | 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
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. |
|

Mar Jun 17, 2008 1:56 am
|
 |
maschino
Perlero Nuevo

|
Registrado: 16 Jun 2008
Mensajes: 4
|
|
|
|
|
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...
El formato del fichero sería algo así:
| Código: |
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. |
|

Mar Jun 17, 2008 4:20 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4092
Ubicación: Valladolid, España
|
|
|
|
|
Pues sí, se puede hacer fácil, pero no ibas desencaminado.
| Perl: | #!/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__ |
| Código: |
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:
| Perl: | if ( $comienzo eq '196' ) {
if ( $comienzo eq ' 0' ) {
if ( $comienzo eq ' ' ) { # para las líneas de los paréntesis
|
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:
| Perl: | 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;
} |
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... |
|

Mar Jun 17, 2008 6:59 am
|
 |
maschino
Perlero Nuevo

|
Registrado: 16 Jun 2008
Mensajes: 4
|
|
|
|
|
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? |
|

Mar Jun 17, 2008 7:16 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4092
Ubicación: Valladolid, España
|
|
|
|
|
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:
| Perl: | $comienzo = substr $linea, 0, 3;
if ( $comienzo =~ /^ *\d+$/ ) { # hay un número con una posible serie de espacios delante
|
|
|

Mar Jun 17, 2008 7:41 am
|
 |
maschino
Perlero Nuevo

|
Registrado: 16 Jun 2008
Mensajes: 4
|
|
|
|
|
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.
Me seguiré pasando por aquí, a ver si aprendo algo más, porque sino...  |
|
Mar Jun 17, 2008 9:19 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4092
Ubicación: Valladolid, España
|
|
|
|
|
| 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. |
|
Powered by phpBB © 2001, 2005 phpBB Group
|