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

Seeking PERL enlightment,

I have a file wherein a certain string (contained in one line only) of specific pattern has to be modified for every new release of SW.

I do not have difficulties in searching for the pattern. But I want to know how to modify this string with the updated SW version with the filehandle enabled for read and write.

original string : SW_V02.03

Upon release of new version, this needs to be modified to : SW_V02.04, SW_V02.05, so on.

Should I use rindex or someother Perl function ?

/HeyRam/

Replies are listed 'Best First'.
Re: Modifying File Contents
by davido (Cardinal) on Mar 18, 2006 at 10:10 UTC

    It could be done pretty simply with a one-liner if I understand the issue correctly (untested):

    perl -pi.bak -e "s/(SW_V)[\d.]+/${1}02.05/" filename.txt

    For the record, the -i switch handles "in-place editing", but it does so in a way that is pretty safe. It actually writes a new outfile, and then renames the input file to whatever.bak, and then renames the output file to the name of the old input file. If you wanted to do it by hand (ie, not as a one liner, and not using the -i switch), you would probably just open the input file and the output file and later use rename to handle the filename swap. ...seems superior to a read/write filehandle.

    Another potential solution is to use Tie::File, and then just wend your way through the array, performing the substitution when the version string is encountered. Tie::File handles the dirty details of in-place editing for you.


    Dave

      I think you could make the solution more general by incrementing what you find in the pattern although this would break if the major version changed or they got to SW_V02.100.
      perl -pi.bak -e 's/(SW_V02\.)(\d\d)/$1 . sprintf("%02d", $2 + 1)/e;' f +ilename.txt
      You may need to change my quotes if not working on Unix.

      Cheers,

      JohnGG

      A neater regex: s/(?<=SW_V)[\d.]+/02.05/

Re: Modifying File Contents
by roboticus (Chancellor) on Mar 18, 2006 at 16:00 UTC
    ramthen--

    Since davido and johngg solved the problem, I won't bother with that. Especially as davido's suggestion was much shorter than I was going to write... 8^)

    But as I've done basically the same task for a client, I thought I'd add one thing: You may want to consider putting guard strings before and after your string, and modifying the regex to require the guard strings. Appropriate guard string selection can help you avoid changing more things than you intended to in your program.

    This may not be a problem in your case, but in our case, we didn't want to inadvertently change data strings along with our serial number.

    --roboticus
      Another safeguard would be to specify that the substitution may happen only once per file. Assuming there is at least one appearance of a version string in the file, and most likely, it's near the very top of the file, that should work and protect you reasonably well.

      I'm thinking that the easiest way to achieve that is to simply slurp the whole file, and process it with a single s///. Source files are usually short enough to not pose any problems. According to perlrun you can use the -0777 switch to slurp the whole file (that's a zero, not a capital O, BTW. I always make that mistake.)

Re: Modifying File Contents
by HuckinFappy (Pilgrim) on Mar 19, 2006 at 03:30 UTC
    Use the IO::InSitu module:
    use IO::InSitu; my ( $src, $dest ) = open_rw( 'my_file', 'my_file' ); while ( my $line = <$src> ) { # If this is the line you want to modify # Call a routine to modify either the minor or # major version, depending on the case in question # by modifying $line print {$dest} $line; }
    Thanks to the Damian for this one!
Re: Modifying File Contents
by artist (Parson) on Mar 19, 2006 at 11:55 UTC
    If you use Version Control Mechanism such as RCS, you can automatically insert the current version with version-header string.
    --Artist