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

Hello everybody, I'm new in here and am very interested in Perl. This code was written in my spare time as an exercise. Please forgive my english mistakes as english is not my first language.
#!perl use strict; use warnings; use File::Find; my @ext = qw(.tmp .bak .$$$ .chk .old .gid .fts .ftg .log .dmp .--- .prv .temp); sub wanted { my $file = $_; map {unlink $file if $file =~ qr/\Q$_\E\z/ and -f $file} @ext; } find(\&wanted, '/');
Thx

Replies are listed 'Best First'.
Re: Can anyone help me to improve this code, please?
by tachyon (Chancellor) on Jun 23, 2004 at 01:22 UTC

    The wanted() sub gets called every time a file/dir is found. Thus the map gets run every time. This is not efficient.

    The typical perl idiom for doing this sort of thing involves making an RE that uses alternation operatior | as in m/this|that|other|thing/. We can automatically generate the RE from your array and also use qr// to compile it.

    ++ for using strict, warnings and modules BTW.

    #!perl use strict; use warnings; use File::Find; my @ext = qw(.tmp .bak .$$$ .chk .old .gid .fts .ftg .log .dmp .--- .prv .temp); # build and compile an RE that uses alternation operator | my $re = join '|', map{ quotemeta } @ext; # compile RE. ?: avoids capture into $1 from ( ) # and the $ locks the matched ext to end of filename $re = qr/(?:$re)$/; sub wanted { return unless -f $_; return unless m/$re/; warn "Unlinking $File::Find::name\n"; unlink $_ or warn "\tUnlink $_ failed $!\n"; } find(\&wanted, '/');

    Typically you want to do a dummy run without unlinking. Trust me on this ;-)

    Update Fixed typo, thanks hv

    cheers

    tachyon

      I would quite likely use a hash instead of a joined OR pattern.

      my %ext; @ext{@ext} = (1) x @ext;
      and then instead of
      return unless m/$re/
      I'd put
      return unless /(\.[^.]+$)/ and $ext{$1};

      ihb

Re: Can anyone help me to improve this code, please?
by Zaxo (Archbishop) on Jun 23, 2004 at 02:21 UTC

    A more aggressive approach is also possible, besides yours and tachyon's. The unlink call can take a list, so lets try unlinking all the unwanted files in each directory we see on the way down the tree.

    #!/usr/bin/perl use strict; use warnings; use File::Find; our @ext = qw(.tmp .bak .$$$ .chk .old .gid .fts .ftg .log .dmp .--- .prv .temp); sub wanted { my $dir = $_; -d && unlink map {glob "$dir/*$_"} @ext; } find (\&wanted, $dir);
    Since find runs wanted() before entering a directory, this approach reduces the number of files find() must look at.

    After Compline,
    Zaxo

Re: Can anyone help me to improve this code, please?
by broquaint (Abbot) on Jun 23, 2004 at 03:27 UTC
    A simpler approach would be to use File::Find::Rule
    my @ext = map "*.$_", qw( .tmp .bak .$$$ .chk .old .gid .fts .ftg .log .dmp .--- .prv .temp ); unlink find(file => name => \@ext, in => '/');
    See. unlink and File::Find::Rule for more info.
    HTH

    _________
    broquaint

Re: Can anyone help me to improve this code, please?
by etcshadow (Priest) on Jun 23, 2004 at 01:58 UTC
    You may not have the standard "find" utility available to you, but just for posterity:
    find / -type f -regex '.*\.\(tmp\|bak\|\$\$\$\|chk\|old\|gid\|fts\|ftg +\|log\|dmp\|---\|prv\|temp\)$' -exec rm \{\} \;
    ------------ :Wq Not an editor command: Wq