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

I have a little script that iterates through a list of files and makes a substitution to lines matching a pattern. It writes the new version of the file over the old, after having saved the old with a .bak extension.

Here's the part that actually does the substitution:

#earlier in the script, we have created #the array of files to edit, and named it @files foreach my $filename (@files) { my $backup = $filename . '.bak'; copy($filename, $backup) unless -e $backup; open(FILE2CHANGE, "<$backup"); open(UPDATED, ">$filename") or die "$filename: $!"; while (<FILE2CHANGE>) { s/foo/bar/g; print UPDATED; } close FILE2CHANGE; close UPDATED; }

To make this script more reusable, I would like to remove the substitution line (s/foo/bar/g) and, instead, have the script read one or more substitution commands from a separate file.

To wit, the substitution file might read:

s/foo/bar/g s/something/something else/

In which case, the script would read these lines and execute them both, upon each file. But I don't want this substitution file to be an executable script in itself; just a data file containing the lines to be used to make the substitution(s).

It's easy enough to read these lines into a array, but is there a way to then run the lines from the variable as if they were lines of code?

Of course, in an ideal world, the script should first make sure the substitution commands look valid, but I haven't even tried to wrap my head around that problem yet...

Thanks,

Lev

Replies are listed 'Best First'.
Re: Run a variable as a line of code?
by Zaxo (Archbishop) on Apr 03, 2006 at 21:13 UTC

    eval

    { open $fh, '<', '/path/to/file' or die $!; for my $cmd (<$fh>) { eval $cmd; } }

    After Compline,
    Zaxo

Re: Run a variable as a line of code?
by CountZero (Bishop) on Apr 03, 2006 at 21:30 UTC
    Did you try $string =~s/$match/$replace/g;?

    You can easily read the $match and $replace values from a file and it is less dangerous than using eval (who knows what someone might have put in that file you just eval-ed?)

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

      If you're worried about someone putting Bad Things in your data file, then you'd need to worry about ?{CODE} just as much as eval STRING.

      "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

      Indeed, you are right and therefore I said less dangerous as it would be marginally easier to filter out "bad" code or recognize "good" code in my suggested approach than in a file to be eval-ed.

      CountZero

      "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: Run a variable as a line of code?
by GrandFather (Saint) on Apr 03, 2006 at 21:16 UTC

    Not answering your immediate question, but a Perl idiom worth knowing is the edit inplace:

    @ARGV = @files; $^I = '.bak'; while (<>) { # do something with each line of each file # The original line contents is in $_ # print prints to the new version of the file s/foo/bar/g; print; }

    Update: Fix @ARGV - thanks QM :)


    DWIM is Perl's answer to Gödel
      Is that supposed to be
      @ARGV = @files;
      ??

      -QM
      --
      Quantum Mechanics: The dreams stuff is made of

      Thanks, GrandFather, but that brings up an interesting thing.

      I liked your code because it was more elegant, so I switched mine to use Perl's edit inplace - but then noticed that the updated file no longer had the original owner.

      My original script kept the original owner on the file, without having to 'chown' it back, and we do need to retain the original owners in this case.

        Sorry, I'm a Windows user and don't generally notice that sort of issue. If no-one replies to the question buried in this thread, repost it as a SoPW in its own right.


        DWIM is Perl's answer to Gödel
Re: Run a variable as a line of code?
by NetWallah (Canon) on Apr 03, 2006 at 21:27 UTC
    You can accomplish what you need to get done using the appropriate variation on this one-liner:
    perl -i.bak -pe "s/OrigTxt/SubsText/g" FileName1.txt FileName2.txt
    So, instead of the "s" commands being in a separate file, you could just have a bunch of one-liners in the file, each one specific to the substitution you need. Cleaner, and more maintainable. Let perl do the work for you.

         "For every complex problem, there is a simple answer ... and it is wrong." --H.L. Mencken

Re: Run a variable as a line of code?
by lev36 (Sexton) on Apr 03, 2006 at 21:50 UTC

    Thanks, all!

    As always, the helpful denizens of the Monastery swiftly provide a range of insights on how to approach a problem, and I'm truly grateful.