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

Hi I am having a couple small issues with a section of code. The issues are
(1.) The .80south backup files are not being created
(2.) The $oldaddr and $newaddr print lines near bottom of the script are empty, The value is not there.
(3.) At one point I had the value there but it was not finding and replacing the entries.
(4.) At one point is was finding and replacing the entries but it wrote back to the file with funny newlines, so the content was all scrambled.

I would appreciate any help you can provide because I just keep fixing one thing only to create a new error

Here is my code section

sub fileFindReplace { my $searchpath = shift; my $ipmapper = shift; #print "searchpath : <$searchpath>\n"; #print "ipmapper : <$ipmapper>\n\n"; find(\&wanted, $searchpath); sub wanted { local (@ARGV) = shift; local ($^I) = ".80south"; open (INPUTFILE, $ipmapper) or die "Could not open file: $!"; my (@mapper) = <INPUTFILE>; foreach my $line (@mapper) { my ($oldaddr, $newaddr,) = split (/\t/, $line, 2); } close INPUTFILE; my $filename = $File::Find::name; return unless -f $filename; return unless $filename =~ /$ARGV/; open (FR, $filename) or print "Could not read $filename\n" && +return; my (@file) = <FR>; close FR; print "read ", scalar(@file), " lines from $filename\n"; open (FW, ">$filename") or print "Could not open for write $fi +lename\n" && return; unless ( open FW, ">$filename" ) { print "could not open $filename for write: $!"; return; } foreach my $find (@file) { print "<MIKE1 Filename is [$filename] \n"; print "<MIKE Searching [$filename] for updates\n"; print "<MIKE Changing OLD IP ADDRESS: $oldaddr\n"; print "<MIKE To NEW IP ADDRESS: $newaddr\n"; $find =~ s/$oldaddr/$newaddr/g; print FW $find; } close FW; } }

Replies are listed 'Best First'.
Re: Find Replace code broke and I cannot seem to fix it
by kennethk (Abbot) on Mar 30, 2010 at 20:57 UTC
    It would be helpful if you provided us with some expected input and output. Running this against strict uncovers two things to consider:
    1. Variable "$ipmapper" will not stay shared at line 19.
      You have used a closure here in passing $ipmapper into your subroutine, and so subsequent calls to fileFindReplace will actually result in a breaking of that link - wanted will hold onto the original copy of $ipmapper while fileFindReplace will create a new one. Consider:
      #!/usr/bin/perl sub print_something { my $x = shift; sub something { return $x; } my $result = something(); print "$x = $result\n"; } print_something(1); print_something(2); __END__ 1 = 1 2 = 1
    2. Global symbol "$oldaddr" requires explicit package name at line 45.
      Global symbol "$newaddr" requires explicit package name at line 46.
      Lexical variables (those declared with my) are scoped to the block level. The variables in question are declared in your foreach loop, and hence they are garbage collected once it has finished. Those variables no longer exist by the time you get to your print and substitution statements. See Variables and Scoping.

    My guess on the substitution problem is because . is a metacharacter in regular expressions and you never escaped them. See perlretut for info. Changing your substitution line to $find =~ s/\Q$oldaddr\E/$newaddr/g; would fix this if this is the issue - details in Quote and Quote like Operators.

    And my guess on .80south backup files is that you're using that wrong. $^I in perlvar references -i in perlrun, which says:

    specifies that files processed by the <> construct are to be edited in-place.
    You don't use the <> operator, so it doesn't do that. I would suggest edit-in-place constructs are likely more clever than you want to be for a real script.
Re: Find Replace code broke and I cannot seem to fix it
by GrandFather (Saint) on Mar 30, 2010 at 21:08 UTC

    Always use strictures (use strict; use warnings;). Don't use global variables in subs. Don't nest named subs - it probably isn't doing what you expect.

    Your 'wanted' sub contains:

    foreach my $line (@mapper) { my ($oldaddr, $newaddr,) = split(/\t/, $line, 2); }

    which slurps a file (bad) then does something with each line from the file and throws away the result ($oldaddr and $newaddr are never used). That seems wrong. Later on a different for loop contains:

    print "<MIKE Changing OLD IP ADDRESS: $oldaddr\n"; print "<MIKE To NEW IP ADDRESS: $newaddr\n";

    which uses $oldaddr and $newaddr, although they are not declared. Note that they are not the variables of the same name used elsewhere.

    So, fix the structural errors and the errors that strictures throw up, then come back with any remaining problems. It would be nice if they were isolated into a chunk of sample code that we can run however!


    True laziness is hard work
Re: Find Replace code broke and I cannot seem to fix it
by toolic (Bishop) on Mar 30, 2010 at 21:07 UTC
    (1.) The .80south backup files are not being created
    Perhaps there is a file permission issue. I do not know how to debug this problem using $^I. I suggest you switch to a more manual approach of creating a backup file, using rename. Then you can check the success of rename to determine if there is a permission issue.