in reply to Trying to substitute a variable with another variable in a string but not working

While it is possible to modify a file in-place, it is simpler and safer to create a new file, then rename the original with a '.bak' extension, then the new file to the name of the original:

open FILE, '<', $file; my $nfile = $file . '.new'; open OFILE, '>', $nfile; while (<FILE>){ if($_ =~ /STARTING_PATTERN\s+(.*)/){ $sub=$1; s/$sub/$cell_name/ ; } print OFILE, $_; } close FILE; close OFILE; rename $file, $file . '.bak'; rename $nfile, $file;

Note that while (<FILE>) is just a short cut for while ($_ = readline(FILE)) so $_ contains a copy of the line as it exists in the file. Any modifications to $_ affect only $_, not the file. In your code, you made a further copy, $string, so you were modifying a copy of a copy.

Modifying a file in-place is tricky to get right even when simply replacing existing bytes. If you are inserting or deleting bytes (which may happen when modifying characters using a variable length encoding like UTF-8), it is a lot trickier.

Replies are listed 'Best First'.
Re^2: Trying to substitute a variable with another variable in a string but not working
by GrandFather (Saint) on Feb 24, 2015 at 23:02 UTC

    Perl is supposed to make easy things easy and in place file editing should be easy shouldn't it? Consider:

    use strict; use warnings; my $cell_name = 'xyzzy'; my $match = 'STARTING_PATTERN'; @ARGV = 'delme.txt'; $^I = '.bak'; while (<>) { s/$1/$cell_name/ if /$match\s+(.*)/; print; }

    Yup, that looks easy.

    Perl is the programming world's equivalent of English

      Different definition of "in place".

      Per perlrun, setting $^I is like including the -i option on the command line. From perlrun:

      specifies that files processed by the <> construct are to be edited in-place. It does this by renaming the input file, opening the output file by the original name, and selecting that output file as the default for print() statements. The extension, if supplied, is used to modify the name of the old file to make a backup copy

      So setting $^I = '.bak' has the same effect as my code. Minor difference: My code reads the original, writes the new, then renames both files. Setting $^I causes the original to be renamed first.

      The "in place" I was referring to is, literally, modifying the existing file where it is stored1. This can be done through careful use of tell and seek. The following should work when replacing existing bytes:

      open my $fh, '<+:raw', $file; # raw so file is read/written in bytes, +not characters my $where = tell($fh); while (<$fh>) { ...; # modify 1 or more bytes seek $fh, $where, SEEK_SET; print $fh, $_; $where = tell($fh); } close $fh;

      If attempting to add or delete bytes, more work needs to be done.

      ---

      1 This ignores the possibility that the underlying storage manager/controller could write the modified blocks of the file to different locations in storage, then update the file's "block map" after the write is successfully completed.

      But what about the danger GrandFather?
Re^2: Trying to substitute a variable with another variable in a string but not working
by kaushik9918 (Sexton) on Feb 25, 2015 at 02:54 UTC
    Thank you for your suggestion. Works fine now.