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

Right: I got this script that I use to check a directory's size and if it's larger than 5mb, compress it, unlink the files once compressed, and write the zip to another directory, reading the names of the previous zips and incrementing the number at the end. However, I have a problem, and I think it's to do with getting parameters as an array. When I shift() to get the files that need to be compressed, I only get the first one. I tried foreaching over them and pushing them onto the array, but still get the same output, only one file getting compressed each time. Is there a procedure for getting lists? I didn't think so, so my problem's probably elsewhere. Here's my code:
use strict; use warnings; use diagnostics; use populate; use Archive::Zip; my($store_path); my(@pictures, $picture); my($cumulative, $size); $store_path = './store'; @pictures = populate($store_path); foreach $picture (@pictures) { $size = (stat($picture))[7]; $cumulative += $size; } &make_barn(@pictures) if ($cumulative >= 5000000); sub make_barn { my($barns_path); my(@pictures, $picture); my($barn_number, @barns); my($barn, $member); @pictures = shift(); # broken $barns_path = './barns'; $barn = Archive::Zip->new(); foreach $picture (shift()) { $member = $barn->addFile($picture); $member->desiredCompressionLevel(9); print "Added $picture\n"; } @barns = populate($barns_path); ($barn_number) = $barns[0] =~ /barn_(.+)\.zip$/; $barn_number++; $barn->writeToFileNamed($barns_path.'/barn_'.$barn_number.'.zip'); }
(populate() is a sub that just slurps every file in a dir into an array, not counting '.' and '..').

Replies are listed 'Best First'.
Re: Recieving lists as arguments
by lhoward (Vicar) on Jul 12, 2001 at 20:46 UTC
    When you call a subroutine, all the arguments passed to it are in the special perl vaiable @_. When you call:
    @pictures = shift(); # broken
    @_ is shifts implied argument (since you didn't supply an argument to shift explicitly). Shift removes and returns the first element of an array. To get the code to work the way you want it to, replace with:
    @pictures = @_;
Re: Recieving lists as arguments
by Masem (Monsignor) on Jul 12, 2001 at 20:45 UTC
Re: Recieving lists as arguments
by the_slycer (Chaplain) on Jul 12, 2001 at 21:05 UTC
    One way to do this is to pass by reference. So, make the call like this
    &make_barn(\@pictures) if ($cumulative >= 5000000);
    Then an assignment to "pictures" would look like.
    $pictures = shift;
    You would then iterate over the array like
    foreach (@{ $pictures }) { #do stuff with $_ }
Re: Recieving lists as arguments
by dsb (Chaplain) on Jul 12, 2001 at 20:59 UTC
    When you pass an array as an argument to sub-routine it gets flattened. That is, as far as the sub-routine knows, its no longer an array, rather its now a list of its scalar elements. So shift will only get the first scalar in the array @_, not the entire list.

    To illustrate:

    @foo = (1,2,3); process_array(@foo); sub process_array { # the special @_ variable now holds (1,2,3), NOT (@foo) $var1 = shift; # $var1 will only get '1'. $var2 = shift; # $var2 will only get '2'. $var3 = shift; # $var3 will only get '3'. }
    To assign the entire argument list you would have to code the sub-routine like this:
    sub process_array { @args = @_; }
    or using an array reference:
    sub process_array { $args = \@_; }
    Hope that helps.

    Amel - f.k.a. - kel

Re: Recieving lists as arguments
by bikeNomad (Priest) on Jul 12, 2001 at 20:50 UTC
    It's not clear what you're doing with both @pictures and $picture. You should remove the line that is marked broken, and change the loop over the pictures to:

    sub make_barn { my($barns_path); my($picture); my($barn_number, @barns); my($barn, $member); $barns_path = './barns'; $barn = Archive::Zip->new(); foreach $picture (@_) { $member = $barn->addFile($picture); $member->desiredCompressionLevel(9); print "Added $picture\n"; }

    And you've made a very good decision to use Archive::Zip :-)

Re: Recieving lists as arguments
by MZSanford (Curate) on Jul 12, 2001 at 22:09 UTC
    Who would i be if i did not put a few more comments on this ? Well, i think lhoward was right about usng array assigment instead of shift. But, something that appears to have been over looked is the calling context.
    In this section, the folloing would happen based on diffrent calling conventions :

    ## Implicit @_ $data = shift; ## Explicit @_ $data = shift(@_); ## Explicit void context $null = shift();
    So, if you in fact only want one, use shift; or shift(@_);
    Calm begets calm