2008-11-10

Examples of Perl: use File::Find

Examples of Perl Program: use File::Find


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