#!/usr/bin/perl =begin metadata Name: find Description: search directory tree for files matching a pattern Author: Greg Snow, snow@biostat.washington.edu Author: Tom Christiansen, tchrist@perl.com Author: Larry Wall, larry@wall.org License: perl =end metadata =cut # find - actually a pass through front end for find2perl use strict; use Config qw(%Config); use File::Basename; use File::Spec::Functions; use File::Temp qw/ tempfile /; use FindBin; sub find_find2perl { return $ENV{FIND2PERL} if defined $ENV{FIND2PERL}; my @candidates = grep { -e } map { catfile( $_, 'find2perl' ) } dirname($Config{perlpath}), split( /$Config{path_sep}/, $ENV{PATH} ) ; push @candidates, catfile( $ENV{PERL_LOCAL_LIB_ROOT}, 'bin', 'find2perl' ) if defined $ENV{PERL_LOCAL_LIB_ROOT}; return defined $candidates[0] ? $candidates[0] : (); } my $find2perl = find_find2perl(); die <<"HEREDOC" unless -e $find2perl; Did not find the find2perl program. Install App::find2perl or set the FIND2PERL environment variable with the path. This program looked for find2perl in: @{[ defined $find2perl ? $find2perl : '<not found>' ]} find2perl was distributed with perl up to v5.18 and became a separate module in v5.20. Older versions of find2perl assumed that the program would be next to the perl binary but installed something like /usr/bin/find2perl that would dispatch to the Standard Library version. HEREDOC # Temp files to capture find2perl output and error. my ($out_fh, $out_file) = tempfile(); my ($err_fh, $err_file) = tempfile(); END { unlink $out_file; unlink $err_file; } # Save STDOUT and STDERR. Redirect to temp files. open SAVE_OUT, '>&', STDOUT or die "Can't save STDOUT: $!"; die unless defined fileno SAVE_OUT; open STDOUT, '>&', $out_fh or die "Can't dup STDOUT to $out_file: $!"; $|++, select $_ for select STDOUT; open SAVE_ERR, '>&', STDERR or die "Can't save STDERR: $!"; die unless defined fileno SAVE_ERR; open STDERR, '>&', $err_fh or die "Can't dup STDERR to $err_file: $!"; $|++, select $_ for select STDERR; # Run find2perl to convert find command to Perl script. system $^X, $find2perl, @ARGV; # Check for errors. my $child_error = $?; my $acm_min_error; open STDERR, '>&', SAVE_ERR or die "Can't restore STDERR: $!"; seek $err_fh, 0, 0 or die "Can't rewind $err_file: $!"; my $error = do { local $/; <$err_fh> }; close $err_fh; if ($error) { if ($error =~ /^Unrecognized switch: -[acm]min\s*$/) { # Tried to use -amin, -cmin or -mmin, which find2perl doesn't # support. $acm_min_error++; # So change to -atime, -ctime or -mtime, and append an # identifier to its argument (fortunately, find2perl does not # validate the argument). for my $i (0..$#ARGV) { $ARGV[$i + 1] .= '-ppt-minutes' if $ARGV[$i] =~ s/^(-[acm])min$/${1}time/; } system $find2perl, @ARGV; $child_error = $?; } else { warn $error; } } die "Can't run $find2perl (wait status == $child_error)" if $child_error; die "Empty program" unless -s $out_fh && -s $out_file; # Get "find" Perl script from output. seek $out_fh, 0, 0 or die "Can't rewind $out_file: $!"; my $program = do { local $/; <$out_fh> }; close $out_fh; open STDOUT, '>&', SAVE_OUT or die "Can't restore STDOUT: $!"; # Convert fake -atime, -ctime and -mtime conditionals, such as: # # (int(-C _) > 60-ppt-minutes) && # (int(-M _) < 15-ppt-minutes) # # To -amin, -cmin and -mmin conditionals, such as: # # (int(1440 * -C _) > 60) && # (int(1440 * -M _) < 15) # if ($acm_min_error) { my $minutes_per_day = 24 * 60; $program =~ s/(\bint\()(-[AMC] .*)-ppt-minutes/$1$minutes_per_day * $2/g; } # Run "find" Perl script. eval qq{ no strict; local \$^W = 0; $program; }; die "Can't compile and execute $find2perl: $@\n" if $@; exit 0; __END__ =head1 NAME find - search directory tree for files matching a pattern =head1 SYNOPSIS B<find> [ -HdhXxW ] [ F<Directory> ] [ expression ] =head1 DESCRIPTION This is actually a front end for B<find2perl>, it automatically converts your request to perl and executes it (unless something goes wrong, you probably will not see a difference). If you want to do something fancier, or are going to do the same search often, you should give the commands straight to B<find2perl> and run the perl code yourself (after possible modification). B<find> searches a directory tree for files matching given criteria, then executes user specified commands on those files. Examples: find and print a list of all files on the system (disk) with a F<.pm> extension (perl modules). C<find / -name "*.pl" -print> find and delete all files in the current directory and subdirectories that end with F<.bak> and have not been accessed in the last 10 days (using unix rm command to do the deleting). C<find . -name "*.bak" -atime +10 -exec rm {};> =head1 SEE ALSO find File/Find.pm =head1 RESTRICTIONS I<find2perl> may not cover all the options that various versions of find implement. It is only a wrapper to find2perl and so has all the same restrictions (some have said that find2perl needs updating). =head1 BUGS This manpage should probably include the entire I<find> manpage, and perhaps that of I<find2perl> as well. =head1 AUTHOR This front-end written by Greg Snow, I<snow@biostat.washington.edu>, with many things "borrowed" from the I<awk> front-end by Tom Christiansen, I<tchrist@perl.com>. The I<find2perl> translator was written by Larry Wall, I<larry@wall.org>, author of Perl. =head1 COPYRIGHT and LICENSE This program is copyright (c) Gregory L. Snow 1999 (with parts "borrowed" from things copyright (c) Tom Christiansen 1999). This program is free and open software. You may use, modify, distribute, and sell this program (and any modified variants) in any way you wish, provided you do not restrict others from doing the same.