Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Search and replace within a file

by muizelaar (Sexton)
on May 08, 2012 at 10:17 UTC ( [id://969404]=perlquestion: print w/replies, xml ) Need Help??

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

Got a problem which I’m not sure why it’s happening and wondered if you could help?

I have written the code below to search the /etc/hosts file to search and replace all entries which have the host name and domain name suffix with what the user has input when the whole script has been run.

For example I want to change the below within the /etc/hosts file

servername.domainsuffix.net servername

to

newname.domainsuffix.org newname

My problem is that where I have placed the $uname (which is the uname –r output from the system) it is not being replaced. However where I have the domain name suffix part which is an actual name it does replace this and $uname replaces the server name after the FQN if you get what I mean.

Apologies if this is not clear it sounds ok in my head :-)

From the example above I get the following Servername.domainsuffix.org newname

open(HST, "<$hosts"); @HOST = <HST>; close(HST); open(HST, ">$hosts"); foreach (@HOST) { s/$uname/$answer1/g; s/domainsuffix.net/$answer4/g; print HST $_; }

Replies are listed 'Best First'.
Re: Search and replace within a file
by aaron_baugher (Curate) on May 08, 2012 at 12:43 UTC

    You don't show the code where you get $uname, but five bucks says it's because `uname -r` is returning a string with a newline on the end, and you aren't chomping it, so it doesn't match when that string is followed by more text. It does work when the text in question happens to be the last text on a line, because in that case it is followed by a newline.

    Aaron B.
    Available for small or large Perl jobs; see my home node.

      Guess what?

      Where would you like me to send your five bucks to?

      You were absolutely correct as soon as I chomped the $uname it started working, thanks so much for this it’s been driving me mad. I’m learning all the time.

Re: Search and replace within a file
by Anonymous Monk on May 08, 2012 at 10:33 UTC

    See quotemeta and Iterator::Diamond

    #!/usr/bin/perl -- use strict; use warnings; use Iterator::Files; my $search = quotemeta `uname -r`; my $input = Iterator::Files->new( files => [ '/etc/hosts' ], ); while( <$input> ){ s/$uname/$answer1/g; s/\Qdomainsuffix.net\E/$answer4/g; }

      Just been reading up on this and it looks very useful, but I’m not sure if this is what I want. Sorry if I haven’t been very clear.

      Where I have s/$uname/$answer/g; it’s the $uname part which is not changing within the hosts file

      However it does change it after the FQN name part within the hosts file

        So you're trying to say that $uname doesn't match as a regular expression?

        Doesn't using quotemeta change that?

        Maybe you want to add case insensitivity (s///i) ?

        See How do I post a question effectively? and write this

        #!/usr/bin/perl -- use strict; use warnings; use Data::Dump qw/ dd /; my $input = 'servername.EXAMPLE.com servername'; my $wantedOutput = 'newname.EXAMPLE.com newname'; my $replacement = 'newname'; my $uname = quotemeta 'servername'; ### dd $input; for( $input ){ s/$uname/$replacement/gi; } dd $input; dd $wantedOutput ; __END__ "servername.EXAMPLE.com servername" "newname.EXAMPLE.com newname" "newname.EXAMPLE.com newname"

        As you can see through my use of Data::Dump::dd, it worked, $input has changed and it now looks like $wantedOutput

Re: Search and replace within a file
by petdance (Parson) on May 08, 2012 at 18:30 UTC
      I thought of recommending the inplace replace using sed. Sorry for recommending sed over perl here.. But I believe this needs to be done in sed than in perl.
      $sed -i 's#uname#newname#' /etc/hosts/*
      I did some time comparison for both perl and sed and it turns out that sed has better performance
      $time sed -i 's/sri/harry/' * sed -i 's/sri/harry/' * 0.00s user 0.01s system 37% cpu 0.016 total $time perl -pi -e 's/harry/sri/' perl -pi -e 's/harry/sri/' * 0.01s user 0.01s system 62% cpu 0.029 to +tal
        But I believe this needs to be done in sed than in perl. [...] I did some time comparison for both perl and sed and it turns out that sed has better performance
        $time sed -i 's/sri/harry/' * sed -i 's/sri/harry/' * 0.00s user 0.01s system 37% cpu 0.016 total $time perl -pi -e 's/harry/sri/' perl -pi -e 's/harry/sri/' * 0.01s user 0.01s system 62% cpu 0.029 to +tal

        So, you suggest to optimize a one-shot command run every few day, weeks, or months for a total execution speed advantage of 10 milliseconds on your machine, based on one single run of each command? Are you serious?

        (If yes, let me suggest to use a one-letter shell alias for "perl -pi -e". This saves you 10 keystrokes and thus gains you much more than 10 milliseconds, even if you can type really fast.)

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: Search and replace within a file
by zwon (Abbot) on May 08, 2012 at 15:26 UTC

    On a side note, let me recommend you File::Slurp module, it allows you to replace the whole your example with:

    use File::Slurp qw(edit_file); edit_file { s/$uname/$answer1/g; s/domainsuffix.net/$answer4/g; } $hosts;
Re: Search and replace within a file
by sundialsvc4 (Abbot) on May 10, 2012 at 12:15 UTC

    As a complete aside, I much prefer to write logic that does not modify a file “in place.”   Even if I very easily can.   I always want to generate a new copy ... a new “generation,” if you prefer ... of that file.   And then to devise the logic so that it subsequently moves the original file aside and moves the new version into its place ... perhaps adding the old version (properly and meaningfully renamed) to a handy nearby zip-file backup.   This approach both saves ammunition and preserves the structural integrity of my foot ... ;-)

      You can achieve the same in a perl one liner
      $perl -e 's/old/new/ -pi.backup /etc/hosts
      It does the inplace replace and takes a back up of the old files with .backup extension

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://969404]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (4)
As of 2024-04-19 04:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found