0

I'm pretty new to Perl but I assumed I had in mind basics like variables definition and scope... but it seems not. My problem is that I keep on bumping into error:

Global symbol "$save_from_date" requires explicit package name at myMover.pl line 40

I've got a function in which I intend to compare a file date versus another date (default or argument), but it's failing.

Here is the troublesome code, extract:

# Process source directory
sub ParseSource {
    my $file = $_;
    my $filedate = localtime( ( stat $file )[9] )->ymd('');
    if ( $filedate >= $save_from_date ) {
        print "[To Archive] $file";
    }
}

#   Default Values
my $source_directory      = 'C:\Users\Public\Documents';
my $destination_directory = 'C:\Users\Public\Documents\Archive';
my $save_from_date        = strftime "%Y%m%d", localtime;
my ( $verboseornotverbose, $display_help ) = undef;

GetOptions(
    "verbose!"            => \$verboseornotverbose,
    "help|h!"             => \$display_help,
    "source_dir|s:s"      => \$source_directory,
    "destination_dir|d:s" => \$destination_directory,
    "date|t:i"            => \$save_from_date
);

usage() if $display_help;

# Basic checks
unless ( -d $source_directory ) { die "ERROR -- Source directory [$source_directory] does not exists" }
unless ( -d $destination_directory ) {
    unless ( mkdir $destination_directory ) {
        die "ERROR -- Destination directory $destination_directory does not exists and couldn't be created'";
    }
}
unless ( $save_from_date <= strftime "%Y%m%d", localtime ) {
    die "ERROR -- Wrong or unknown date format [$save_from_date] should be before or equal today\'s' date'";
}
print $save_from_date ;

# Here we parse the source directory
find( \&parseSource, $source_directory );

This is the comparison that is failing: if ($filedate >= $save_from_date)

Could you please explain me what I missed in that sub ?

I've read many other posts and some variables definition tutorials but I couldn't get the clue of my problem...

Thank you !

Miller
  • 34,962
  • 4
  • 39
  • 60
Maxime
  • 25
  • 3
  • 3
    Function definitions need to be located after the declarations of the global variables they use. – nobody Oct 20 '14 at 13:07

2 Answers2

6

The variable is not declared when the sub is being parsed. Either move the variable declaration before the sub, or pass the variable to the sub as a parameter.

Update: You can't pass parameters to the wanted sub in File::Find directly. But, you can wrap it in an anonymous sub:

sub parseSource {
    my $save_from_date = shift;
    # ...
}

# ...

find( sub { parseSource($save_from_date) }, $source_directory );
choroba
  • 231,213
  • 25
  • 204
  • 289
  • Thanks ! That was it all simple... thought Perl was kind of behaving like shell script and I could define subroutines/function and then use it regardless of the global variables I'll be using in... I was guessing wrong. Much obliged, I think I'll keep on reading some tutorials... – Maxime Oct 20 '14 at 13:24
  • 4
    If you turn off `strict` and `warnings` you can do all sorts of dirty things that'll mostly work. Except when they don't, and you'll have a horrible job tracking it back and figuring out why. – Sobrique Oct 20 '14 at 13:34
  • 1
    You can pass parameters - more or less. Instead of passing `\&ParseSource` as the `wanted` sub, try `sub { ParseSource($save_from_date, @_) }` - technically, you're passing an anonymous code ref, but it's still calling the code you want with the extra parameter. – Tanktalus Oct 20 '14 at 14:38
0

As has already been explained, you must declare your variables before using them inside subroutines.

I would also like to demonstrate that you can simplify your GetOptions code by initializing them and passing a reference in the same step:

GetOptions(
    "verbose!"            => \( my $verboseornotverbose ),
    "help|h!"             => \( my $display_help ),
    "source_dir|s:s"      => \( my $source_directory = 'C:\Users\Public\Documents' ),
    "destination_dir|d:s" => \( my $destination_directory = 'C:\Users\Public\Documents\Archive' ),
    "date|t:i"            => \( my $save_from_date = strftime "%Y%m%d", localtime ),
);

usage() if $display_help;

# Basic checks
die "ERROR -- Source directory [$source_directory] does not exists"
    unless -d $source_directory;

mkdir $destination_directory
    or die "ERROR -- Destination directory $destination_directory does not exists and couldn't be created'"
    unless -d $destination_directory;

die "ERROR -- Wrong or unknown date format [$save_from_date] should be before or equal today\'s' date'"
    unless $save_from_date <= strftime "%Y%m%d", localtime;

# Process source directory
sub ParseSource {
    my $file = $_;
    my $filedate = localtime( ( stat $file )[9] )->ymd('');
    if ( $filedate >= $save_from_date ) {
        print "[To Archive] $file";
    }
}
Miller
  • 34,962
  • 4
  • 39
  • 60