Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Sort files by oldest timestamp

by srianju (Initiate)
on May 06, 2009 at 05:01 UTC ( [id://762163]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, I have 2 requirements. First one is I need to move one file at a time to a different file share in order to process the file through ETL. Second is I need to move oldest file first. Below is my code.The files are moving but not by last modification time and also giving 2 different types of error messages. If I don't use "Use Strict",then here is the message I am getting.
C:\PERL\bin>perl.exe "c:\1file@atime.pl" -e Global symbol "@sorted" requires explicit package name at c:\1file@ati +me.pl line 17. Global symbol "@sorted" requires explicit package name at c:\1file@ati +me.pl line 26. Global symbol "$xmlfile" requires explicit package name at c:\1file@at +ime.pl lin e 30. Global symbol "@sorted" requires explicit package name at c:\1file@ati +me.pl line 30. Global symbol "$xmlfile" requires explicit package name at c:\1file@at +ime.pl lin e 31. Global symbol "$xmlfile" requires explicit package name at c:\1file@at +ime.pl lin e 35. Execution of c:\1file@atime.pl aborted due to compilation errors.
If I commented out "Use Strict",then it gives below message but files are moving not by sorted time stamp
C:\PERL\bin>perl.exe "c:\1file@atime.pl" -e Use of uninitialized value in numeric comparison (<=>) at c:\1file@ati +me.pl line 17. Use of uninitialized value in numeric comparison (<=>) at c:\1file@ati +me.pl line 17. File Name: ebert_conc.con moved to FTP - 30 mins for next upload. File Name: ebert.xyz moved to FTP - 30 min for next upload.
Here is my script
#!/usr/bin/perl use warnings; use strict; use File::Copy; my $srcdir = "\\\\windowsservername\\directory\\Subdirectory\\"; my $dest = "C:\\Documents and Settings\\"; for (;;) { opendir(DIR, $srcdir) or die "Can't open $srcdir: $!"; my @files = grep {!/^\.+$/} readdir(DIR); @sorted = reverse(sort{ -M $a <=> -M $b #( $m{$a} ||= -M $a ) <=> # ( $m{$b} ||= -M $b ) } @files); close(DIR); if (!@sorted) { print "Files have been ended.\n\n"; last; } $xmlfile = $sorted[0]; my $old = "$srcdir/$xmlfile"; move($old, $dest) or die "Move $old -> $dest failed: $!"; print "File Name: $xmlfile moved to Fileshare - 30 mins for next u +pload.\n\n"; sleep 1800; # 30 Minutes }
I have tried couple other ways but not successful and sure where I am doing wrong.I am using perl version 5.8.8. Any help would be appreciated. Regards, Sree

Replies are listed 'Best First'.
Re: Sort files by oldest timestamp
by ig (Vicar) on May 06, 2009 at 10:36 UTC

    I used Perl::Tidy to reformat your script, making it easier to read.

    #!/usr/bin/perl use warnings; use strict; use File::Copy; my $srcdir = "\\\\windowsservername\\directory\\Subdirectory\\"; my $dest = "C:\\Documents and Settings\\"; for ( ; ; ) { opendir( DIR, $srcdir ) or die "Can't open $srcdir: $!"; my @files = grep { !/^\.+$/ } readdir(DIR); @sorted = reverse( sort { -M $a <=> -M $b #( $m{$a} ||= -M $a ) <=> # ( $m{$b} ||= -M $b ) } @files ); close(DIR); if ( !@sorted ) { print "Files have been ended.\n\n"; last; } $xmlfile = $sorted[0]; my $old = "$srcdir/$xmlfile"; move( $old, $dest ) or die "Move $old -> $dest failed: $!"; print "File Name: $xmlfile moved to Fileshare - 30 mins for next uploa +d.\n\n"; sleep 1800; # 30 Minutes }

    You should be using closedir to close the directory handle, rather than close. But I don't think this is causing your problem.

    As Marshall has pointed out, your tests for file modification time are not using the correct paths. This is the probable cause of the "Use of uninitialized value in numeric comparison (<=>) at c:\1file@atime.pl line 17." errors you are getting. Prepend the directory to the file names in the tests and you will probably find that your list is sorted.

    You could use glob to get the filenames, rather than reading the directory. Glob can return paths, rather than just file names. Something like the following is an alternative:

    my $oldestfile; my $oldestage; foreach my $file (glob("$srcdir/*.xml")) { if( !defined($oldestfile) or -M $file > $oldestage ) { $oldestfile = $file; $oldestage = -M $file; } }
Re: Sort files by oldest timestamp
by moritz (Cardinal) on May 06, 2009 at 06:21 UTC
    Global symbol "@sorted" requires explicit package name

    This basically means "you did not declare variable @sorted". So you need to put a my in front of the first occurrence of @sorted, $xmlfile and so on.

Re: Sort files by oldest timestamp
by codeacrobat (Chaplain) on May 06, 2009 at 05:54 UTC
    try
    sort {(-M $a) <=> (-M $b)}
    Update
    Imho it is better to use stat to test the files. -M uses the $^T special variable, which is set once at the start of the script. For long running scripts this is not recommended. Try this (untested):
    #!/usr/bin/perl use warnings; use strict; use File::Copy; my $srcdir = "\\\\windowsservername\\directory\\Subdirectory\\"; my $dest = "C:\\Documents and Settings\\"; LOOP: while (1) { undef $!; my %fileage = map { ($_ => (stat)[9]) } glob "$srcdir\\*.*"; die "can't glob $srcdir $!" if $!; my $xmlfile = (sort { $fileage{$a} <=> $fileage{$b} } keys %fileag +e)[0]; unless (defined $xmlfile){ print "Files have been ended.\n\n"; last LOOP; } my $old = "$srcdir/$xmlfile"; move( $old, $dest ) or die "Move $old -> $dest failed: $!"; print "File Name: $xmlfile moved to Fileshare - 30 mins for next uploa +d.\n\n"; sleep 1800; # 30 Minutes }

    print+qq(\L@{[ref\&@]}@{['@'x7^'!#2/"!4']});
      ok, ok, I know, it's way old but I can't resist to say this:
      Your code does the LOOP as many times as there are files in the srcdir and it does a stat for ever file in srcdir in every LOOP as long as the file has not been moved yet (i.e. n! with n files). So if you have very many files in your srcdir, let's say 1,000,000 or so you will have a lot of unnecessary overhead.

      pelagic
Re: Sort files by oldest timestamp
by Marshall (Canon) on May 06, 2009 at 07:29 UTC
    You have some "brain twisting" stuff here.

    First, I would suggest using /, forward slash instead of \\. This is portable and will work on Windows.

    Now, what do you you think this does?

    opendir(DIR, $srcdir) or die "Can't open $srcdir: $!"; my @files = grep {!/^\.+$/} readdir(DIR);
    This looks pretty good, but readdir doesn't give a full path..@files is just some names within the $srcdir. If you want to use @files, and do some kind of a test like -M, you will need to prepend the $srcdir to get a full path name!
      Thank you everyone who responded with answers.As Marshall said,the issue is not having full path.My issue is resolved after prepend the $srcdir to get a full path name. Thank you for the help!.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://762163]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (3)
As of 2024-04-26 01:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found