Some additional fixes for the Search script I recently posted. Ero Brown #======================================================================== #======================================================================== # # Search.pl # # Author: Ero Brown <ero@fiber.net> # # Version: 2.2 # # Special thanks to Paul J. Schinder, Chris Nandor, and # Ronald J. Kimball who's suggestions helped make this a much better # script. Also, thanks to Raffael Cavallaro, RenŽ Laterveer, # Jay Bedsole, Richard Gordon, and Thomas R. Kimtpon for their # helpful comments. Changes from the original are too numerous # to list! # #======================================================================== #======================================================================== #!/usr/local/bin/perl ### required modules needed for this script use File::Find; use File::Basename; use Getopt::Long; #======================================================================== ### Forward declare all sub-routines used sub Usage; sub ReadArguments; sub DoAFile; sub SearchFilter; #======================================================================== # Function: Usage # Purpose: this details the usage of this script -- we can call this # function when a invalid usage error occurs. #======================================================================== sub Usage { die <<END_USAGE; usage: $0 [-r] [-c] [-i] [-s] [-m] [-p] [-f <expression>] -e <expression> <folder(s) &| file(s) . . .> -r recursively process encountered sub-directories -c only list a total count of matching occurrances -i make pattern matching case insensitive -s print summary information only -m mpw style output -p print progress and summary information -f file expression representing a file filter -e the expression representing what you are searching for *Parameters can be given in any order. *Fully resolved pathnames are required, partial pathnames will cause this script to barf. Version 2.2 END_USAGE } #======================================================================== # Function: ReadArguments # Purpose: Parse the arguments array and set the appropriate flags. #======================================================================== sub ReadArguments { #if no arguments are passed in, assume the user needs some help if (@ARGV < 1) { Usage; } $res = Getopt::Long::GetOptions("r", "c", "i", "s", "m", "p", "f=s" => \$fileFilter, "e=s" => \$expression); if (!$res) { Usage; } $recurseOpt = $opt_r; $countOnlyOpt = $opt_c; $caseInSensitive = $opt_i; $summaryInfoOnly = $opt_s; $mpwOutputOpt = $opt_m; $progressOpt = $opt_p; $fileFilterOpt = $fileFilter ne ''; $expressionOpt = $expression ne ''; $pad = ""; if ($progressOpt) { $pad = "\t"; } $lst = ""; if ($mpwOutputOpt) { $lst = "# "; } #if no directories/files are passed in, assume the user needs some help if (@ARGV < 1) { print "# At least one directory or file to search must be specified.\n"; Usage; } if (!$expressionOpt) { print "# The required -e expression option was NOT specified.\n"; Usage; } } #======================================================================== # Function: DoAFile # Purpose: process the file/directory # this is where the action is -- look at every file and # directory and perform the desired operations. #======================================================================== sub DoAFile { my ($theFile) = @_; my ($shortName, $tempFName, $doSearch, $found, $lineCount, $tFoundCount); if (-f $theFile) { $fileCount++; if ($progressOpt) { print $pad, $lst, "FILE: $theFile\n"; } $shortName = File::Basename::basename($theFile); if ($summaryInfoOnly) { $tempFName = $theFile; } else { $tempFName = $shortName; } $doSearch = 1; if ($fileFilterOpt) { $doSearch = 0; if ($caseInSensitive) { if (eval($shortName =~ /$fileFilter/oi)) { $doSearch = 1; } } else { if (eval($shortName =~ /$fileFilter/o)) { $doSearch = 1; } } } if ($doSearch) { $tFoundCount = 0; $lineCount = 1; if ($progressOpt) { print $pad, $pad, $lst, "Searching $shortName...\n"; } if (open(THEFILE, "< $theFile\0")) { while ($lineStr= <THEFILE>) { $found = 0; if ($caseInSensitive) { if (eval($lineStr =~ /$expression/oi)) { $found = 1; } } else { if (eval($lineStr =~ /$expression/o)) { $found = 1; } } if ($found) { $tFoundCount++; if (!$countOnlyOpt && !$summaryInfoOnly) { if (length($lineStr) > 255) { $lineStr = "### LINE TOO LONG TO PRINT ###\n"; } if ($mpwOutputOpt) { print $pad, $pad, "File \"", $theFile, "\"; "; print "Line ", $lineCount, ":¤ \t# ", $lineStr; } else { print $pad, $pad, $theFile, " -- line #"; print $lineCount, "\n", $pad, $pad, $pad, $lineStr; } } } $lineCount++; } close(THEFILE); if (($progressOpt || $summaryInfoOnly) && ($tFoundCount > 0)) { if ($mpwOutputOpt && $summaryInfoOnly) { print $pad, $pad, "OPEN \"", $theFile, "\" \t# -- "; print $tFoundCount, " occurrances of the search "; print "expression.\n"; } else { print $pad, $pad, $lst, $tempFName, " -- had ", $tFoundCount; print " occurrances of the search expression.\n"; } } $foundCount += $tFoundCount; } else { $errorCount++; if ($progressOpt || $summaryInfoOnly) { print $pad, $pad, "# ERROR! couldn't open: \"$tempFName\"; print " -- $!\n"; } } } } # it must be a directory (-d $theFile) else { $dirCount++; if ($progressOpt) { print $lst, "DIRECTORY: $theFile\n"; } } } #======================================================================== # Function: SearchFilter # Purpose: We need to provide this function for the File::Find::find() # function in the File::Find module -- this is so we can control # (via filter) what kind of files and/or directories get handled. #======================================================================== sub SearchFilter { #filter so we only process the files/directories we want ( ( -e $_ && -s $_ ) && ( ( -f $_ && -r $_ && -T $_ ) || ( -d $_ && -x $_ && ( $recurseOpt || ( !$recurseOpt && ($File::Find::prune = 1) ) ) ) ) ) && DoAFile($File::Find::name); #call our function that does the checking } #======================================================================== #============================ MAIN ================================== #======================================================================== ### main part of the program -- ### we go through every file and directory passed in on ### the command line and check it for validity. #what OS are we running on? $osString = $^O; #parse the command line for commands and arguments ReadArguments; if ($progressOpt) { print $lst, "Executing this script on a computer running $osString...\n"; } #initialize these counter variables $fileCount = 0; $dirCount = 0; $unknownCount = 0; $errorCount = 0; $foundCount = 0; #process every directory (and/or file) provided on the command line while (@ARGV) { $arg = shift(@ARGV); #get the next directory/file to examine if ((-f $arg) || (-d $arg)) { #check for a valid disk entity File::Find::find(\&SearchFilter, $arg); #'find' calls "SearchFilter" } #which we use as a filter and to call our "DoAFile". else { $unknownCount++; print STDERR "# ERROR: \"$arg\" wasn't a recognized file or directory.\n"; } } if ($progressOpt || $summaryInfoOnly || $countOnlyOpt) { print $lst, "FOUND $foundCount occurrances of \"$expression\" "; print "in the specified files.\n"; } if ($progressOpt || $summaryInfoOnly) { print $lst, "Examined $fileCount files, and $dirCount directories"; if ($errorCount > 0) { print " -- encountered $errorCount errors"; } print ".\n"; if ($unknownCount > 0) { print $lst, "There were $unknownCount "; print "non-files/non-directories encountered.\n"; } print "\n"; } exit; #======================================================================== #======================================================================== ***** Want to unsubscribe from this list? ***** Send mail with body "unsubscribe" to mac-perl-request@iis.ee.ethz.ch