Hello Monks!
Spent a few hours at work on several occasions debugging some scripts that are almost as old as I am, and have found a quirk that I don't really understand.
Essentially, we pull a "string of numbers" from an argument given at the command line, and then do various things based on what's contained in that string.
An example of the borked code is as follows:
#!/usr/bin/perl
# I know there should be
# use strict;
# and
# use warnings;
sub process {
my ($fileName) = @_;
open FILE, $fileName or die $!;
while (<FILE>) {
chomp $_;
my @parts = split(',', $_);
for (@parts) {
# Do some stuff
}
}
}
sub finalize {
print "Finished\n";
}
my $runlvl = $ARGV[0];
if ($runlvl == 1) {
# Do everything
$runlvl = "23";
}
die "Invalid arguments"
unless ($runlvl =~ /^\d+$/);
# For conversations sake, lets just read this script
my $filename = $0;
print "Run level: $runlvl\n";
# Do some stuff based on the runlevel
for ($runlvl) {
/2/ and process($filename);
/3/ and finalize();
}
print "Run level: $runlvl\n";
When I run this with a single command line parameter of "1", I'd expect it to get to that poor-man's switch at the bottom and do a process() and finalize(), however only the "2" matches. By the time it gets to the "3", $runlvl is empty.
The output of the above is:
$ perl broken.pl 1
Run level: 23
Run level:
Though it took a while to figure out where things were going pear-shaped, the below seems to work as expected. Note the difference in the while() loop in that first subroutine
#!/usr/bin/perl
sub process {
my ($fileName) = @_;
open FILE, $fileName or die $!;
while (my $line = <FILE>) {
chomp $line;
my @parts = split(',', $line);
for (@parts) {
# Do some stuff
}
}
}
sub finalize {
print "Finished\n";
}
my $runlvl = $ARGV[0];
if ($runlvl == 1) {
# Do everything
$runlvl = "23";
}
die "Invalid arguments"
unless ($runlvl =~ /^\d+$/);
# For conversations sake, lets just read this script
my $filename = $0;
print "Run level: $runlvl\n";
# Do some stuff based on the runlevel
for ($runlvl) {
/2/ and process($filename);
/3/ and finalize();
}
print "Run level: $runlvl\n";
Wahoo! This time it outputs:
$ perl not_broken.pl 1
Run level: 23
Finished
Run level: 23
So I guess the actual question I want to ask is why is that first while loop that uses the somewhat magick $_ rather than it's own local variable clobbering the value of $runlvl? Or is it clobbering @ARGV? Or.. Is that weird switch thing trying to match on $_ rather than "whatever is in runlevel"?
This ones got me stumped - any wisdom would be greatly appreciated.