File::Find is used for searching through directory trees doing work
on each file found similar to the Unix find command. Find has two arguments. It accepts a code reference to your own code as the first argument and the directories as the second argument as below: find ( \&wanted, @directories ); This is my example to search the files by specified pattern (.txt files) in a directory (my backup) in a defined period (1 month).
Here is the main to set up test data and call find:
#!/usr/bin/perl -w ############################################################# # Example ############################################################# use strict; use File::Find; # We have to do it this way passing parameters # because the wanted function takes no arguments # and the return value is ignored. our ( $search_path, $search_filepattern, $search_destdir, %search_timepattern, $search_maxdepth, $search_action, @filelist ); # Following sector is testing data # Get processing period of epoch time my %search_timepattern = CalPeriod( "2008", "03" ); # Define which directory to be searched my $search_path = "/home/backup/"; # Set max search depth as no sub directories my $search_maxdepth = 3 ; # search pattern: all .txt file my $search_filepattern = ".txt\$"; # The destination directory to move files my $search_destdir = "/tmp/"; # The array to return matched files my @filelist; # The folowing action when a matched file is found # We use "copy" for testing. my $search_action = "copy"; # Now, search and take action on matched files @filelist = find(\&wanted, $search_path); |
This part is the wanted function:
sub wanted { # DESCRIPTION: search for files with given pattern in a directory hierarchy # This subroution is File::Find wanted function. Do not use it directly. # # PARAMETERS: # our ($search_path, $search_filepattern, $search_destdir, %search_timepattern, $search_maxdepth, $search_action, @filelist); # The wanted function takes no arguments and the return value is ignored. # # $search_path: searching path # $search_filepattern: string of a pattern to match file name. # eg. search .txt file, $sesarch_filepattern = ".txt\$" # %search_timepattern('begin','end'): the time range to match file modification time # $search_maxdepth: the max depth of recursive subdirectory search. # 2 is "/*/*/", 3 is "/*/*/*/", so on # $search_action: following action on matched file: copy, move, print # $search_destdir: the destination directory if following action is copy/move # @filelist: RETURN an array of matched files ############################################################# use File::Spec; use File::Copy; use File::stat; # to limit recursive subdirectory search by defined max_depth my $depth = $File::Find::dir =~ tr[/][]; return if $depth > $search_maxdepth; # get the original file time stamp my $atime = stat($File::Find::name)->atime; my $mtime = stat($File::Find::name)->mtime; # get the destination file name if move/copy found file my $dest_file = $search_destdir.$_; my @dest_file = $dest_file; if ( ( -f $File::Find::name ) # matches file only && ( $File::Find::name =~ /$search_filepattern/ ) # matches defined pattern && ( ($mtime ge $search_timepattern{begin}) && ($mtime le $search_timepattern{end}) ) # matches file time stamp ) { # Take actions on matched file # copy if ( $search_action eq "copy" ) { printf("Copying...%s to %s \tatime: %s, mtime: %s\n",$File::Find::name,$dest_file,$atime,$mtime); copy($File::Find::name, $dest_file) or die "Copy failed: $!"; utime $atime, $mtime, @dest_file; # keep original time stamp } # move if ( $search_action eq "move" ) { printf("Moving...%s to %s\n",$File::Find::name,$dest_file); move($File::Find::name, $dest_file) or die "Move failed: $!"; utime $atime, $mtime, @dest_file; # keep original time stamp } # print file name if ( $search_action eq "print" ) { printf("%s\n",$File::Find::name); } # return file list push(@filelist, $File::Find::name); } } |
Here is some subroutines to process time. It is not necessary to use File::Find.
sub CalPeriod { # DESCRIPTION: Get one month's start time and end time of epoch # PARAMETERS: string of year no, string of month no, # RETURN: hash of period # $period{begin} The epoch time of first second in a month. # $period{end} The epoch time of last second in a month. # (leap second doesn't count). # USAGE: %period = CalPeriod($YYYY,$MM); ############################################################# use Time::Local; my $year = shift(@_); my $month = shift(@_); my $days = DayInMonth($month,$year); my %t1 = ( 'year' =$year, 'mmon' = $month - 1, # month number start from 0 'day' = '01', 'hour' = '00', 'min' = '00', 'sec' = '00' ); my %t2 = ( 'year' = $year, 'mmon' = $month - 1, # month number start from 0 'day' = $days, 'hour' = '23', 'min' = '59', 'sec' = '59' ); my $time_begin = timelocal($t1{sec},$t1{min},$t1{hour},$t1{day},$t1{mmon},$t1{year}); my $time_end = timelocal($t2{sec},$t2{min},$t2{hour},$t2{day},$t2{mmon},$t2{year}); my %period = ( 'begin' = $time_begin, 'end' = $time_end ); return %period ; } sub DayInMonth { # DESCRIPTION: get the days in a month (leap year is calculated) # PARAMETERS: string of month no, string of year no # RETURN: string of days # USAGE: $days = DayInMonth($month,$year); ############################################################# my $month = shift(@_); my $year = shift(@_); my $days = 31; if ( $month =~ /^(4|04|6|06|9|09|11)$/ ) { $days = $days - 1; } elsif ( $month =~ /^(2|02)$/ ) { $days = 29; if ((($year%4)!=0) || (($year%100)==0)) { $days = $days - 1; } } return $days; } sub PreMonth { # DESCRIPTION: get the no of last month # PARAMETERS: string of month no # RETURN: string of last month no # USAGE: $lastmonth = PreMonth($month); ############################################################# my $mon = shift(@_); my $m = $mon - 1; if ( $m < 1 ) { $m = 12; } $m =~ s/^\d$/0$&/ ; return $m; } |
No comments:
Post a Comment