• Publicidad

Problemas con el 8 y el 9

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

Problemas con el 8 y el 9

Notapor lis » 2008-12-21 16:27 @727

Hola a todos, tengo el siguiente script que hice para descargar datos de todo un año y todo funciona bien hasta que llega al mes de agosto, en donde he variado las formas de escribir el 8 que corresponde a ese mes pero siempre me sale esto: Use of uninitialized value in foreach loop entry at ./demas.pl line 15. Aquí esta el script:

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

use strict;
my ($syscmd, $vn, $opt, @filelist);
my $web = "https://dss.ucar.edu/datazone/dsszone/ds083.2/";
$opt = " --header 'Cookie: duser=mercedesbenz4370\@gmail.com' -nc";
open VN, "wget -V |" or die 'cannot find wget';
$vn = (<VN> =~ /^GNU Wget (\d+)\.(\d+)/) ? (100 * $1 + $2) : 109;
close(VN);
$opt = ($vn > 109 ? '--no-check-certificate --no-cookies' : '--cookies=off') . $opt;

foreach my $ano ( "05" ) {
    my @dias_del = qw (0 31 28 31 30 31 30 31 31 30 31 30 31);
    foreach my $mes ( "01" .. "12" ) {
        foreach my $dia ( "01" .. $dias_del[$mes] ) {
            foreach my $hora ( 12 ) {
                foreach my $ceros ( "00" ) {
                    my $datos= "$ano"."$mes"."$dia"."_"."$hora"."_"."$ceros";

                    @filelist = ( "2005/2005.$mes/fnl_$datos", );

                    for(my $i = 0; $i < @filelist; $i++) {
                        $syscmd = "wget $opt $web$filelist[$i]";
                        print "$syscmd...\n";
                        system($syscmd);
                    }
                }
            }
        }
    }
}
exit 0;
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Por favor, ayúdenme y muchas a gracias a todos.
lis
Perlero nuevo
Perlero nuevo
 
Mensajes: 106
Registrado: 2008-05-27 21:43 @946

Publicidad

Notapor explorer » 2008-12-21 20:39 @902

Pues no veo el error... y en mi Perl 5.10 tampoco me lo da.

Lo único que se me ocurre es ir reduciendo el código, para hacerlo menos propenso a errores:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;

my $web = q(https://dss.ucar.edu/datazone/dsszone/ds083.2);
my $opt = q(--header 'Cookie: [email protected]' -nc);
my @dias_del = qw (0 31 28 31 30 31 30 31 31 30 31 30 31);

open VN, "wget -V |" or die 'cannot find wget';
my $vn = (<VN> =~ /^GNU Wget (\d+)\.(\d+)/) ? (100 * $1 + $2) : 109;
close(VN);
$opt = ($vn > 109 ? '--no-check-certificate --no-cookies' : '--cookies=off') . ' ' . $opt;

for my $ano  ( 5                     ) {
for my $mes  ( 1  .. 12              ) {
for my $dia  ( 1  .. $dias_del[$mes] ) {
for my $hora ( 12                    ) {

    my @filelist = (
        sprintf("%4d/%4d.%02d/fnl_%02d%02d%02d_%02d00", (2000+$ano), (2000+$ano), $mes, $ano, $mes, $dia, $hora),
    );

    for my $file ( @filelist ) {
        my $syscmd = "wget $opt $web/$file";
        print "$syscmd\n";
        system($syscmd);
    }
}}}}

exit 0;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Hay un problema: hay que editarlo cada vez que se quiera cambiar de año. Y tener en cuenta si ese año es bisiesto o no.

Se puede hacer algo más simple: que Perl haga esas cuentas, por nosotros:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;

use POSIX qw(strftime);
use Time::Local;

my $web = q(https://dss.ucar.edu/datazone/dsszone/ds083.2);
my $opt = q(--header 'Cookie: [email protected]' -nc);

open VN, "wget -V |" or die 'cannot find wget';
my $vn = (<VN> =~ /^GNU Wget (\d+)\.(\d+)/) ? (100 * $1 + $2) : 109;
close(VN);
$opt = ($vn > 109 ? '--no-check-certificate --no-cookies' : '--cookies=off') . ' ' . $opt;

@ARGV or die "Uso: $0 año\n";
my $ano_inicial = shift @ARGV;
my $ano;
my $inicio = timelocal(0,0,12,1,0,$ano_inicial);

do {
    my $file = strftime "%Y/%Y.%m/fnl_%y%m%d_%H%M", localtime $inicio;

    my $syscmd = "wget $opt $web/$file";
    print "$syscmd\n";
    system($syscmd);

    $inicio += 86_400;

    $ano = 1900 + (localtime($inicio))[5];

} while ($ano == $ano_inicial);

exit 0;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
Aquí, le damos al programa el mes que queremos bajarnos (no probado), y se encarga de ir de día en día, desde el uno de enero de ese año, hasta el siguiente año.

Pero aún así... queda demasiado espeso... muchas cuentas y excepciones. Seguro que hay más formas de hacerlo.

Una solución intermedia es usar Date::Calc:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;

use Date::Calc qw( Add_Delta_Days Days_in_Year );

## Constantes
my $web = q(https://dss.ucar.edu/datazone/dsszone/ds083.2);
my $opt = q(--header 'Cookie: [email protected]' -nc);

open VN, "wget -V |" or die 'cannot find wget';
my $vn = (<VN> =~ /^GNU Wget (\d+)\.(\d+)/) ? (100 * $1 + $2) : 109;
close(VN);
$opt = ($vn > 109 ? '--no-check-certificate --no-cookies' : '--cookies=off') . ' ' . $opt;

## Año pasado por el usuario
@ARGV or die "Uso: $0 año\n";
my $ano = shift @ARGV;

## Rango de fechas
my @inicio = ($ano,  1,1);
my $dias   = Days_in_Year($ano,12);

## Recorrer los valores
for my $i ( 0 .. $dias-1 ) {
    my @fecha = Add_Delta_Days(@inicio, $i);

    my $file  = sprintf "%4d/%4d.%02d/fnl_%02d%02d%02d_1200",
                    $fecha[0], $fecha[0], $fecha[1],
                    substr($fecha[0],2,2), @fecha[1,2];

    my $syscmd = "wget $opt $web/$file";
    print "$syscmd\n";
    system($syscmd);
}

exit 0;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Mi favorito es usar siempre el módulo DateTime:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;

use DateTime;

## Constantes
my $web = q(https://dss.ucar.edu/datazone/dsszone/ds083.2);
my $opt = q(--header 'Cookie: [email protected]' -nc);

open VN, "wget -V |" or die 'cannot find wget';
my $vn = (<VN> =~ /^GNU Wget (\d+)\.(\d+)/) ? (100 * $1 + $2) : 109;
close(VN);
$opt = ($vn > 109 ? '--no-check-certificate --no-cookies' : '--cookies=off') . ' ' . $opt;

## Año pasado por el usuario
@ARGV or die "Uso: $0 año\n";
my $ano_inicial = shift @ARGV;

## Empezamos el primero de año
my $dia = DateTime->new(
    day   => 1,
    month => 1,
    year  => $ano_inicial,
    hour  => 12,
    minute=> 0,
);

## Bucle
do {
    my $file = $dia->strftime("%Y/%Y.%m/fnl_%y%m%d_%H%M");

    my $syscmd = "wget $opt $web/$file";
    print "$syscmd\n";
    system($syscmd);

    $dia->add( days => 1 );

} while ($dia->year() == $ano_inicial);

exit 0;
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


Volver a Básico

¿Quién está conectado?

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

cron