in reply to Re: Using pattern match
in thread Using pattern match

Thank you all for your help.

Now I am trying to add another intricacy, that is user input:
#!/usr/bin/perl -w # builtin triggers my %triggers; # add triggers from params my $trigger_name = shift @ARGV; my $trigger_action_str = shift @ARGV; my $trigger_action = sub { $trigger_action_str }; $triggers{$trigger_name} = $trigger_action; #print "$trigger_name -> $trigger_action_str\n"; my $buff = "You are fired!"; foreach my $trigger ( keys ( %triggers ) ) { if ( $buff =~ /$trigger/ ) { #print "Memory contents of \$1: $1\n"; print &{$triggers{$trigger}}; } } print "\n";
If I try to run this:
perl triggers2.pl "You are (\w+)." "You are: $1"
it doesn't work.
Any advice, please? Would the eval solution work with this?
Cheers,

tceng

Replies are listed 'Best First'.
Re^3: Using pattern match
by FunkyMonk (Chancellor) on Aug 10, 2007 at 12:26 UTC
    The shell is eating $1. Escape the dollar: \$1 or use single quotes on the command line.

      Hm,

      actually what I get is:
      You are: $1
      If I escape the dollar sign, I get:
      You are: \$1
      I am using Windows here, but I was asking myself if it will work when I read from file, for it's what I really need with the script.
      I'll have a go at it.
      Thanks!

      tceng
Re^3: Using pattern match
by akho (Hermit) on Aug 10, 2007 at 14:15 UTC
    Yes, you will definitely need string eval here.

    Something like this:

    #!/usr/bin/perl -w use strict; # builtin triggers my %triggers; # add triggers from params my $trigger_name = shift @ARGV; my $trigger_action_str = shift @ARGV; $triggers{$trigger_name} = $trigger_action_str; my $buff = "You are fired!"; foreach my $trigger ( keys ( %triggers ) ) { if ( $buff =~ /$trigger/ ) { print eval '"' . $triggers{$trigger} . '\n"'; } }

    But this is not a design anyone will recommend.

    Besides, this will not run in taint mode.

      Thanks akho. I ended up with this, can you please advise?
      #!/usr/bin/perl -w use strict; # builtin triggers my %triggers; # add triggers from params my $trigger_name = shift @ARGV; my $trigger_action_str = shift @ARGV; $triggers{$trigger_name} = sub { eval $trigger_action_str; }; my $buff = "You are fired!"; foreach my $trigger ( keys ( %triggers ) ) { if ( $buff =~ /$trigger/ ) { print &{$triggers{$trigger}}; } }
      If I try:
      perl triggers2.pl "You are (\w+)." "\"You are: $1\""
      I get:
      You are: fired

      Correct. You see, I just have to add escaped quotes on the command line. But is this one a good way to go, pls?

      Cheers,

      tceng
        You can add the quotes in sub's definition.

        This is not a very good idea for the same reasons as my eval-based solution above: it's insecure (there was a comment above about that) and the interface (the way you call triggers.pl) depends on the implementation in weird ways (the user has to use numbered variables).

        This is ok if you just want to learn about dispatch tables, but production code should be better designed.

Re^3: Using pattern match
by Anonymous Monk on Aug 10, 2007 at 14:37 UTC
    the eval() solution would work in the above case, but be advised that this approach is even eviler than (string) eval() used on its own. this is because code can be evaluated at run time both in eval() and in the extended regex pattern (?{{ code... }}).

    see the subject of taint checking and perlsec for more horrific details.

      Thanks for your feedback, it's very interesting and appreciated.
      The script will run as server and therefore I'd like it to tun in tainted mode, so I figured out another way to do things:
      #!/usr/bin/perl -w -T use strict; # builtin triggers my %triggers; # add triggers from params my $trigger_name = shift @ARGV; my $trigger_action_str = shift @ARGV; $triggers{$trigger_name} = $trigger_action_str; my $buff = "You are fired!"; foreach my $trigger ( keys ( %triggers ) ) { if ( $buff =~ /$trigger/ ) { my $c1 = $1; my $txt = $triggers{$trigger}; $txt =~ s/\$1/$c1/g; print $txt; } }
      Yes, that's not elegant for I should save each memory container $1, $2, and so on to be general enough, but at least I can run it in tainted mode:
      perl -T triggers4.pl "You are (\w+)." "Your status: $1"

      So I get:
      Your status: fired

      Cheers,
      tceng