Quoth bernd <
bew...@gmx.net>:
>
> I have two perl progs, both expected to do the same, eval()ing a
> pattern substitution expression using variables for the substitution
> pattern and the replacement (to be used in a subroutine later on).
I don't know what you're trying to do, but I'm *certain* there's a
better way of doing it. Maybe if you explained why you're doing this
someone could suggest a less-insane alternative.
> The first prog uses 'use strict' and lexical variables and looks like
> this:
>
> #!/usr/bin/perl -w
>
> use strict;
> my $old = 'test this one';
> my $pat = 'this';
> my $repl = 'that';
> my $mods = '';
> my $new;
>
> eval('($new = $old) =~ s/$pat/$repl/ee . $mods');
>
> print $new . "\n";
>
> ($mods can take a string containing one or more modifiers (like 'g')
> to the s/// operator).
>
> The output is
>
> Use of uninitialized value in substitution iterator at (eval 1) line
> 1.
> test one
OK, you have multiple levels of 'eval' here, so we need to step through
them carefully to understand what's going on.
First we eval the single-quoted string
'($new = $old) =~ s/$pat/$repl/ee . $mods'
Since this is single-quoted there's no interpolation, so the eval has
exactly the same effect as writing the code out normally. (Did you mean
the '. $mods' to come outside the string?) So now we are executing
($new = $old) =~ s/$pat/$repl/ee . $mods
s///ee starts by interpolating $pat on the LHS, so we're searching for
/this/
(as a regular expression). For each instance it finds, it runs
eval "$repl"
(note the double-quotes, they're important). This is equivalent to
eval 'that'
which is equivalent to
that;
as a standalone Perl statement.
Since this is all under 'use strict "subs"', and there is no 'sub that'
in scope, this throws a 'Bareword "that" not allowed while "strict subs"
in use' error. The eval catches the error, stuffs it into $@, and
returns undef. The s///ee takes the undef and inserts it into $new in
place of the 'this' it found, which gives an 'uninitialized value'
warning.
> In the second version I dispensed with 'use strict' and lexical
> variables:
The reason this 'worked' is not because you stopped using 'strict
"refs"' and lexicals, but because you stopped using 'strict "subs"'.
Perl 4 had a completely bizarre bit of behaviour: if it saw an
expression like
that;
and there was no 'sub that' defined, it assumed you had meant
'that';
and carried right on. This means that once the chain of evals above gets
that far, it simply turns the bareword back into a string (without
complaining) and you get the substitution you were expecting.
Now, how much of that did you want? I suspect you will get what you
meant if you just remove the 'ee' (and put the $mods outside the
string), but the whole thing is enormously unsafe. What if someone gives
you a $pat of
'//; system "rm -rf /"; s/'
?
Ben