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

Hello Perl Monks, I want to write a script which can modify an entry in a file. For Ex: The file test.txt contains a single line: Identity = "Winged" My perl script has to find the string Identity in the file test.txt and replace the word next to = to say ABC. Below is my perl script; but got stuck at replacing the word section. Dont know how to go about modifying it in the file.
#!/usr/bin/perl $ModFile = $ARGV[0]; $Setting = $ARGV[1]; open FH, ">$ModFile" or die "Cannot open $ModFile.\n"; while (<FH>) { if($_ =~ /^Identity/i) { chomp($_); /=(.*?)$/; ####$1 contains everything after =; but dont #know how to +replace it. } }
Please guide me regarding this.

Replies are listed 'Best First'.
Re: Modifying entries in a file.
by prasadbabu (Prior) on Jan 12, 2006 at 11:14 UTC

    nisha, in the fourth line you have opened file in write mode '>' (which will remove the existing content in the file). So you change it '<' else remove it (default is read mode), and proceed. Also take a look at perlre and perlopentut

    #!/usr/bin/perl $ModFile = $ARGV[0]; $Setting = $ARGV[1]; open (FH, "<", "$ModFile") or die ("Cannot open $ModFile.\n"); open FOUT, ">", "$Setting" or die ("Cannot open $Setting.\n"); while (<FH>) { $text = $_; chomp($text); if($text =~ /^Identity/i) { $text =~ s/=(.*?)$/= ABC/s; } print FOUT $text; }

    TIMTOWTDI

    #!/usr/bin/perl $ModFile = $ARGV[0]; $Setting = $ARGV[1]; open (FH, "<", "$ModFile") or die ("Cannot open $ModFile.\n"); open FOUT, ">$Setting" or die "Cannot open $setting.\n"; $text = do {local $/; <FH>}; $text =~ s/^(Identity\s*\=)[^\n]*$/$1 ABC/si; print FOUT $text;

    Prasad

Re: Modifying entries in a file.
by jonadab (Parson) on Jan 12, 2006 at 12:36 UTC

    This really is two questions. First, you want to know how to make a modification to a string, and second, you want to know how to write to a file. (Modifying a file in place is harder, something that as a beginning Perl programmer you will probably want to leave for later.)

    The second question, writing to a file, has already been addressed by the other answers. For what you're doing, you basically will loop through the input file, and write each line, either modified or not, out to the output file. (Then, if you're brave, you can move the modified output overtop of the input, but for now I would probably leave that to do manually after inspecting the output.)

    However, nobody seems to have addressed the first question, making the modification to the string in the first place. You can do this with a regular expression substitution...

    $_ =~ s/=.*?$/=Whatever/;

    Also note that the substitution operator binds to $_ by default, so if you're operating on $_ you may leave off the $_ =~ part. (If you want to operate on the contents of any _other_ variable, though, you'd have to specify it.) Note too that since the pattern that I'm substuting for starts with =, I had to include the = in the substitution, since otherwise it would be removed. It is possible to avoid this (by excluding the = from the pattern (using a lookbehind assertion)), but the way I've written it here is easier to understand and should work just as well. The only caveat is that you do have to leave this inside the if statement that checks for your keyword (Identify in your example), but you had that already. Using the lookbehind would allow you to combine that step with the substitution:

    $_ =~ s/(?<=Identity=).*?$/Whatever/;

    However, there are limitations to this approach (e.g., you can't straightforwardly allow an optional space before the = sign, as the other version implicitely does), and the only tangible benefit is terseness. So on the whole I would tend to go the other way, putting the substitution inside the if block and including the = in both the pattern and the replacement string.

    As for writing to the file, you can just write $_ out to the output file after the close of the if block, so that it's written whether it's been modified or not. That way the whole contents of the input file is copied over to the output file, except that it's modified if any changes are made to $_ in the if block. It's also possible to chain several elsif blocks onto the if block, thereby allowing for several possible changes. More complex variations (e.g., using a hash or array as a list of changes to make) are beyond the scope of this reply.

    HTH.HAND.


    "In adjectives, with the addition of inflectional endings, a changeable long vowel (Qamets or Tsere) in an open, propretonic syllable will reduce to Vocal Shewa. This type of change occurs when the open, pretonic syllable of the masculine singular adjective becomes propretonic with the addition of inflectional endings."  — Pratico & Van Pelt, BBHG, p68
Re: Modifying entries in a file.
by tirwhan (Abbot) on Jan 12, 2006 at 11:22 UTC

    You could use

    perl -pi -e 's/^(Identity\s*=).*$/$1 ABC/' test.txt

    See perldoc perlrun on how the various command-line switches for perl work.


    There are ten types of people: those that understand binary and those that don't.
Re: Modifying entries in a file.
by john_oshea (Priest) on Jan 12, 2006 at 11:26 UTC

    You may want to look at Tie::File, which will handle the file reading and writing for you, and leave you to work on a simple array. If not, you'll have to write out the unchanged file contents yourself, as well as the stuff you're actually changing. You'll also have to change your existing open statement, as you're currently going to be truncating the contents of $ModFile when you hit that line which is probably not what you want ;-)

    Hope that helps