Your biggest problem is that you edit $_
, so the second pass through the loop, there is no longer a "Ix" nor "Ay" in the string.
$loop=0;
while ($loop < $max) {
my $local = $max-$loop;
my $line = $_;
$line =~ s/Ix/I$loop/;
$line =~ s/Ay/A$local/;
print "$line\n";
$loop++;
}
You might also consider using a for
loop:
for my $loop (0 .. ($max - 1)) {
my $local = ($max - $loop);
my $line = $_;
$line =~ s/Ix/I$loop/;
$line =~ s/Ay/A$local/;
print "$line\n";
}
If these are space-delimited "columns" and you'd like to only edit the values in "columns" 2 and 3 (your mention of $2
in awk
seems to suggest that?) you can split the input as well: the split
command intentionally emulates awk
From perldoc -f split
:
As another special case, "split" emulates the default behavior of
the command line tool awk when the PATTERN is either omitted or a
literal string composed of a single space character (such as ' '
or "\x20", but not e.g. "/ /"). In this case, any leading
whitespace in EXPR is removed before splitting occurs, and the
PATTERN is instead treated as if it were "/\s+/"; in particular,
this means that any contiguous whitespace (not just a single space
character) is used as a separator. However, this special treatment
can be avoided by specifying the pattern "/ /" instead of the
string " ", thereby allowing only a single space character to be a
separator.
If omitted, PATTERN defaults to a single space, " ", triggering
the previously described awk emulation.
which brings us to:
local $" = ' '; #" (syntax highlighting bug on SO)
my @input = split;
if ($input[1] =~ /Ix/) {
for my $loop (0 .. ($max - 1)) {
my $local = ($max - $loop);
my @line = @input;
$line[1] =~ s/Ix/I$loop/;
$line[2] =~ s/Ay/A$local/;
print "@line\n";
}
} else {
print "$_\n";
}
The special variable $"
specifically means that "@line"
will be printed with a ' '
between each element of the array, so you get your "columns" back in the output.
One last hint: your die
can print a meaningful error message just by including $!
:
#!/usr/bin/perl -w
use strict;
my $loop=0;
my $max=3;
my $in_file="$ARGV[0]";
local $" = ' '; #" (syntax highlighting bug on SO)
open (PH, "$in_file") or die "check file: $!";
while (<PH>) {
chomp;
my @input = split;
if ($input[1] =~ /Ix/) {
for my $loop (0 .. ($max - 1)) {
my $local = ($max - $loop);
my @line = @input;
$line[1] =~ s/Ix/I$loop/;
$line[2] =~ s/Ay/A$local/;
print "@line\n";
}
} else {
print "$_\n";
}
}
close(PH);
Edit:
As @Kenosis pointed out in comments, the sample output you provided has the I
counter running 1…3 rather than 0…2. In your loop, you were initializing the counter to 0 and incrementing it only after printing, so I had (mis-)interpreted that as your intention.
Fortunately, changing this is easy:
for my $loop (1 .. $max) {
my $local = (1+ $max - $loop);
…
As also pointed out, using lexical (my
) variables for file handles is generally safer/better for various technical reasons, as well;
open my $ph, '<', $infile or die "Can't read $infile: $!";
…
while (<$ph>) {
…
… although the older style filehandles that you used (bareword identifiers) still does work.
This also shows the "3-argument open
", which prevents a number of possible security holes (or bizarre, head-scratchingly crazy behaviours) in the "2-arg" form, with the <
prepended to the filename.
And, as @Kenosis notes, $"
does happen to default to ' '
, but I tend to redefine it "just in case" (I personally have a lot of Perl code that redefines it as things like ','
or "\t"
for various reasons, and you can local
ly reset it to be sure of what your output will look like.)