开发者

Perl - Why does shift lose its value after being used?

开发者 https://www.devze.com 2022-12-12 13:22 出处:网络
This code works - It takes an array of full txt file paths and strips them so that when $exam_nums[$x] is called, it returns the file name

This code works - It takes an array of full txt file paths and strips them so that when $exam_nums[$x] is called, it returns the file name

for (0..$#exam_nums)
{
 $exam_nums[$_] =~ s/\.txt$//; #remove extension
 $exam_nums[$_] =~ s/$dir//g; #remove path
}

When I try to do this for a single variable, it doesn't work. I'm calling a subroutine and sending it a present, but the variable is empty at the end. (It is getting into the if statement block, because the other lines in there run fine.) 开发者_高级运维 Here's the code:

Call to the sub:

notify($_);

The $_ is from a foreach(@files) loop that works

The sub:

sub notify
{
 if(shift)
 { 
  $ex_num = shift;
  $ex_num =~ s/\.txt$//; #remove extension
  $ex_num =~ s/$dir//g; #remove path
        print $ex_num;
        print "\nanything";
 }
}

I tried taking out the $ in the "remove extension" portion of the regex, but that didn't help.


You're shifting TWICE. The first shift in the if statement removes the value, the second shift gets nothing. shift has a side-effect of actually modifying @_. in addition to returning the first element, it removes the first element permanently from @_.

EDIT: from man perlfunc

   shift ARRAY
   shift   Shifts the first value of the array off and returns it,
           shortening the array by 1 and moving everything down.  If there
           are no elements in the array, returns the undefined value.  If
           ARRAY is omitted, shifts the @_ array within the lexical scope
           of subroutines and formats, ...


You are attempting to extract your ex_num argument from @_ (the argument list) twice: shift (which alters @_) is not the same as $_[0] (which just looks at the first element of @_ but does not alter it). See perldoc -f shift.

Also, your function is closing over $dir, which may or may not be your intent. (See perldoc perlfaq7 for more information about closures.) I've taken that out and added it as an additional function parameter:

sub notify
{
    my ($ex_num, $dir) = @_;
    return unless $ex_num;

    $ex_num =~ s/\.txt$//; # remove extension
    $ex_num =~ s/$dir//g;  # remove path
    print $ex_num . "\n";
}


I'd use File::Basename instead of rolling my own. It allows you to parse file paths into their directory, filename and suffix.


As per Jim Garrison's info, I pulled a switch to fix the problem:

sub notify
{
    $ex_num = shift;
    if($ex_num)
    {   
        $ex_num =~ s/\.txt$//; #remove extension
        $ex_num =~ s/$dir//g; #remove path
    }
}


Uses a core module, local variables and Perl 5.10.

use 5.010;
use File::Basename;

sub notify {
    my $ex_num = shift;
    my $name = basename($ex_num, '.txt');
    say $name;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消