skyler has asked for the wisdom of the Perl Monks concerning the following question:

I have an error message that I don't undestand why it is happening. "Global symbol $dir requires a explicit package name ....in line 47" I have defined $dir as scalar variable... Do you have any sugestions...???
#! perl -w use strict; use File::Find; use File::Copy; my $infile = 'c:/doclist1.chr'; open IN, "<$infile" or die "Couldn't open $infile, $!"; while(<IN>) { chomp; my @fields = split /,/; my $path_str = $fields[6]; do { warn "Empty field 7"; next } unless $path_str; my @path = split /\\/, $path_str; # assuming you want to remove a few directories my @directory = join "\\", @path[0,5,6]; } exit; close IN; my @dir = @directory; my $srcfile; sub process_file { foreach my $dir (@dir) { if ($File::Find::dir ne $dir) { $File::Find::prune = 1; return 0; } return 0 if ($_ !~ /\.rtf$/); copy($File::Find::name, "C:\\testfiles\\$_") or die "Failed to cop +y $_: $!\n"; return 1; } find(\&process_file, $dir); }

Title edit by tye

Replies are listed 'Best First'.
Re: copy files
by pfaut (Priest) on Feb 24, 2003 at 23:49 UTC

    I'm assuming line 47 is find(\&process_file, $dir); which has a reference to $dir but is just past the foreach loop. The $dir declared in foreach my $dir ... goes out of scope at the end of the foreach loop. It is no longer in scope at line 47.

    --- print map { my ($m)=1<<hex($_)&11?' ':''; $m.=substr('AHJPacehklnorstu',hex($_),1) } split //,'2fde0abe76c36c914586c';
      Dear pfaut, I've been working on this code for the past two days... do you have any suggestion on what do I need to rearrange my code to make it compile. If I rearrange my code I could get it to copy only one file but it stops there. The idea is to keep going until the end of the array and copy every file it get from the source directory to the target one. I'll appreciate your suggestions. Many Thanks

        First please learn the value of indenting you code properly so you can see the flow. If you don't know how get a copy of perltidy from sourceforge and let it do it for you till it comes naturally. Try something like this:

        #! perl -w use strict; use File::Copy; my $infile = "c:\\doclist1.chr"; my @directories; # first lets build our directory list open IN, "<$infile" or die "Couldn't open $infile, $!"; while (<IN>) { chomp; my @fields = split /,/; my $path_str = $fields[6]; do { warn "Empty field 7"; next } unless $path_str; my @path = split /\\/, $path_str; # push the directories into an array push @directories, join "\\", @path[ 0, 5, 6 ]; } close IN; # now we have a directory list in @directories let's process it for my $dir ( @directories ) { process_dir($dir); } exit; sub process_dir { my $dir = shift; do { warn "$dir does not exist!\n"; return } unless -e $dir; opendir DIR, $dir or do { warn "Could not open $dir $!\n" ; return + }; while ( my $file = readdir DIR ) { next unless -f "$dir\\$file"; next unless $file =~ m/\.rtf$/; copy( "$dir\\$file", "C:\\testfiles\\$file" ) or die "Failed to copy $file: $!\n"; } }

        Once you have the basic logic working you can add in File::Find if you need to recurse a directory structure in your process dirs sub. There were a lot of problems with your code. Foremost was that you wanted to push a list of directories into @directory but were not pushing and even if you were the my declaration in the loop would erase it every loop.

        You actually don't need @directories at all a you can just call process_dirs() in your main loop like this:

        #! perl -w use strict; use File::Copy; my $infile = "c:\\doclist1.chr"; open IN, "<$infile" or die "Couldn't open $infile, $!"; while (<IN>) { chomp; my @fields = split /,/; my $path_str = $fields[6]; do { warn "Empty field 7"; next } unless $path_str; my @path = split /\\/, $path_str; my $dir = join "\\", @path[ 0, 5, 6 ]; process_dir($dir); } close IN; sub process_dir { my $dir = shift; do { warn "$dir does not exist!\n"; return } unless -e $dir; opendir DIR, $dir or do { warn "Could not open $dir $!\n" ; return + }; while ( my $file = readdir DIR ) { next unless -f "$dir\\$file"; next unless $file =~ m/\.rtf$/; copy( "$dir\\$file", "C:\\testfiles\\$file" ) or die "Failed to copy $file: $!\n"; } }

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

        Just move the $dir declaration up a line.
        my $dir; # my goes here foreach $dir (@dir) { # my does not go here. if ($File::Find::dir ne $dir) { $File::Find::prune = 1; return 0; }
Re: copy files
by jasonk (Parson) on Feb 25, 2003 at 00:22 UTC

    You declared $dir using 'foreach my $dir (@dir) {', which limits the declaration to inside that foreach loop, then you attempted to pass it to find(), which is outside the loop.