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

Is there anyway to shorten this script? I think this script could be reduced to 1/6th the size, but I am not too sure what the best method is... a little lesson on perl technique anyone?

"In God we trust, all others bring data." -trowa
#!/usr/local/bin/perl # rmtree is not ideal because directory doesn't need to be unlinked, o +nly files # use File::Path; # $verbose=1; # $safe=0; # rmtree([ $dir_split, $dir_vn1, $dir_vn2, $dir_vn3, $dir_vn4, $dir_vn +5, $dir_vn6 ], $verbose, $safe); my $dir_split='/opt/stats/data/split'; my $dir_vn1='/opt/stats/data/split/vn1'; my $dir_vn2='/opt/stats/data/split/vn2'; my $dir_vn3='/opt/stats/data/split/vn3'; my $dir_vn4='/opt/stats/data/split/vn4'; my $dir_vn5='/opt/stats/data/split/vn5'; my $dir_vn6='/opt/stats/data/split/vn6'; # opendir DIR0, $dir_split || die "Cannot open $dir_split: $!"; my @files=grep {-f "$dir_split/$_" } readdir DIR0; closedir DIR0; chomp(@files); chdir("$dir_split"); unlink @files or die "unlink unsuccessful: $!"; # opendir DIR1, $dir_vn1 || die "Cannot open $dir_vn1: $!"; my @files=grep {-f "$dir_vn1/$_" } readdir DIR1; closedir DIR1; chomp(@files); chdir("$dir_vn1"); unlink @files or die "unlink unsuccessful: $!"; # opendir DIR2, $dir_vn2 || die "Cannot open $dir_vn2: $!"; my @files=grep {-f "$dir_vn2/$_" } readdir DIR2; closedir DIR2; chomp(@files); chdir("$dir_vn2"); unlink @files or die "unlink unsuccessful: $!"; # opendir DIR3, $dir_vn3 || die "Cannot open $dir_vn3: $!"; my @files=grep {-f "$dir_vn3/$_" } readdir DIR3; closedir DIR3; chomp(@files); chdir("$dir_vn3"); unlink @files or die "unlink unsuccessful: $!"; # opendir DIR4, $dir_vn4 || die "Cannot open $dir_vn4: $!"; my @files=grep {-f "$dir_vn4/$_" } readdir DIR4; closedir DIR4; chomp(@files); chdir("$dir_vn4"); unlink @files or die "unlink unsuccessful: $!"; # opendir DIR5, $dir_vn5 || die "Cannot open $dir_vn5: $!"; my @files=grep {-f "$dir_vn5/$_" } readdir DIR5; closedir DIR5; chomp(@files); chdir("$dir_vn5"); unlink @files or die "unlink unsuccessful: $!"; # opendir DIR6, $dir_vn6 || die "Cannot open $dir_vn6: $!"; my @files=grep {-f "$dir_vn6/$_" } readdir DIR6; closedir DIR6; chomp(@files); chdir("$dir_vn6"); unlink @files or die "unlink unsuccessful: $!";

Replies are listed 'Best First'.
Re: arrays within arrays?
by hdp (Beadle) on Apr 26, 2001 at 02:42 UTC
    There are two really big red flags here (thanks Dominus). First, you have a group of variables that are all named similarly; you should be using an array instead, e.g. @dir_vn (which would then have 6 elements). If they were named similarly but were distinguished by some "property name" (instead of a number, as here) you would probably want a hash; for example, $animal_name, $animal_color, $animal_food becomes %animal with name, color, and food as keys. Second, you're repeating essentially the same block of code six times! Ouch. Clearly you need some sort of loop. Happily, you recognized that something's not quite right here.

    It turns out that you don't even need the array at all; the only place it ends up being used is in the loop control statement. See below.

    #!/usr/local/bin/perl my $dir_split = '/opt/stats/data/split'; for $dir ($dir_split, map { $dir_split . "/vn$_" } 1..6) { opendir DIR, $dir or die $!; my @files = grep -f "$dir/$_", readdir DIR; # the chomp was unnecessary closedir DIR; chdir($dir); unlink @files or die $!; }
    hdp.
      Yes, that is awesome... I would never have come up with something that concise. on a side note, i noticed that when the last line is changed from:
      unlink @files or die $!;

      to:
      unlink @files || die $!;
      it runs without any errors, but does not delete anything. what is the difference between or and ||? or, is it all in my imaginition? Much Thanks,

      -trowa

      "In God we trust, all others bring data."
        See perldoc perlop. || has a rather high precedence. or is lower. When using the former, it's as if you'd written unlink(@files || die $!) which will never die as long as @files is true.

        hdp.

Re: arrays within arrays?
by MeowChow (Vicar) on Apr 26, 2001 at 03:35 UTC
    Perl isn't always the best tool for the job. Try this from the shell:
    find -type f -maxdepth 2 -path './vn[1-6]*' -exec rm {} \;
       MeowChow                                   
                   s aamecha.s a..a\u$&owag.print
      I like the perl method because of the advantages you can get with using arrays. But I also like the shell method because it seems much more efficient. Either way, I have learned two new things today. very much thanks for both of your insights....

      -trowa
Re: arrays within arrays?
by Rhandom (Curate) on Apr 26, 2001 at 08:37 UTC
    This is a little shorter, possibly faster, definitely nicer on memory on big directories, plus it spits out what is going on (would have been shorter without the print)

    #!/usr/local/bin/perl use File::Find qw(find); my $dir_pre = '/opt/stats/data/split/vn; my @dirs = (); push @dirs, $dir_pre.$_ for (1..6); find( sub{ next unless -f; print "unlinking \"$_\"\n"; unlink $_ || warn $!; }, @dirs);


    my @a=qw(random brilliant braindead); print $a[rand(@a)];
      Okay, I'm going to try a little benchmark test today. Three differents ways are better then one. These scripts have been invaluable, thanks... "In God we trust, all others bring data." - trowa