I have been trying to get rid of a we开发者_StackOverflow社区ird bug for hours, with no success. I have a subroutine that sorts a file. here is the code:
sub sort_file {
$filename = @_;
print @_;
print $filename;
open(SRTINFILE,"<$filename");
@lines=<SRTINFILE>;
close(SRTINFILE);
open(SRTOUTFILE,">$filename");
@sorted = sort { @aa=split(/ /,$a); @bb=split(/ /,$b); return ($aa[1] <=> $bb[1]); } @lines;
print SRTOUTFILE @sorted;
close(SRTOUTFILE);
}
any time this function is run, perl creates a file, called "1". i have no idea why. I am a complete perl noob and am just using it for quick and dirty text file processing. anyone know what's wrong?
An array in scalar context evalutes to the number of elements in the array. If you pass one argument to the function, the following assigns 1
to $filename
.
$filename = @_;
You want any of the following:
$filename = $_[0];
$filename = shift;
($filename) = @_;
Furthermore, you want to limit the scope of the variable to the function, so you want
my $filename = $_[0];
my $filename = shift;
my ($filename) = @_;
(my $filename) = @_; # Exact same as previous.
The other answers are sufficient to tell you why you were getting strange errors.
I would like to show you how a more experienced Perl programmer might write this subroutine.
use warnings;
use strict;
use autodie;
sub sort_file {
my( $filename ) = @_;
my @lines;
{
# 3 arg open
open my $in_fh, '<', $filename;
@lines = <$in_fh>;
close $in_fh;
}
# Schwartzian transform
my @sorted = map{
$_->[0]
} sort {
$a->[2] <=> $b->[2]
} map {
[ $_, split ' ', $_ ]
} @lines;
{
open my $out_fh, '>', $filename;
print {$out_fh} @sorted;
close $out_fh;
}
}
use strict;
prevents you from using a variable without declaring it (among other things).use warnings;
Informs you of some potential errors.use autodie;
Now you don't need to writeopen .... or die ....
{ open ...; @lines = <$fh>; close $fh }
Limits the scope of the FileHandle.@sorted = map { ... } sort { ... } map { ... } @list
This is an examples of a Schwartzian transform, which reduces the number of times that the values are split. In this example, it may be overkill.
How confusing. Assigning $filename = @_
the way you are means that you are evaluating an array in scalar context, which means that $filename
is assigned the number of elements in @_
. Because you don't check to see if the first open
call succeeds, reading the file 1
likely fails, but you continue anyway and open for writing a file named 1
. The solution is to use $filename
in an array context and begin your subroutine with ($filename) = @_
or $filename = shift
.
Why aren't you using use strict
by the way?
Always use:
use strict;
use warnings;
Then Perl will tell you when you're off the mark.
As you've observed, the notation:
$filename = @_;
means that an unscoped variable is assigned the number of elements in the argument list to the function, and since you pass one file, the name of the created file will be '1'.
You meant to write:
my($filename) = @_;
This provides list context for the array, and assigns $_[0]
to $filename
, ignoring any extra arguments to the function.
OK... nevermind. it just dawned on me. $filename = @_;
makes no sense. should be $filename = @_[0];
. There goes 2 hours of my life. note to other perl noobs: beware.
精彩评论