11

The Situation

I am in the process of creating a simple template file that will aid in creating future scripts for doing various tasks via command line on *nix systems. As part of this, I might like to ask the user to input data which needs to validated against a regular expression that is supplied in the source code.

The Issue

Errors are begin generated when I attempt to run the Perl code via command line. I am attempting to pass a regular expression into the repeat subroutine and I'm not sure how to exactly do this. I am aware that I can execute a string using eval, however this is something that I would like to avoid due to convention.

The errors:

Use of uninitialized value $_ in pattern match (m//) at scripts/template line 40.
Use of uninitialized value $resp in concatenation (.) or string at scripts/template line 37.

The code:

#!/usr/bin/env perl

use strict;
use warnings;
use Cwd;
use Term::ANSIColor;
use Data::Dumper;

my $log = "template.log";
my $task = "template";
my $cwd = getcwd();
my $logPath = $cwd . "/". $log;

print ucfirst($task) . " utility starting...\n";
system("cd ~/Desktop");
system("touch " . $log);
&writeLog("Test");

sub writeLog {
    open(my $fh, '>>', $logPath) or die "Could not open file '$log' $!";
    print $fh $_[0] . localtime() . "\n";
    close $fh;
    return 1;
}

sub ask {
    my $question = $_[0];
    my $input = $_[1];
    my $resp = <>;
    chomp($resp);
}

sub repeat {
    my $pat = $_[0];
    my $resp = $_[1];
    print $pat . "\n";
    print $resp . "\n";
}

&repeat(/foo|bar/i, "y");

What I have tried:

Based on these sources:


sub repeat {
    my $pat =~ $_[0];
    my $resp = $_[1];
    if($pat !~ $resp) {
        print "foo\n";
    } else {
        print "bar\n";
    }
}

Any help is appreciated!

Community
  • 1
  • 1
djthoms
  • 3,026
  • 2
  • 31
  • 56
  • This `&repeat(/foo|bar/i, "y");` is not passing a regex, this is passing the result of `$_ =~ /foo|bar/i` . – foibs Dec 17 '13 at 23:49
  • 2
    I would also note that if you allow the user to enter regexes, you're essentially saying "please type in code and I will execute it." qr/?{ system "rm -rf *" }/ is going to make for an unhappy day. – Joe McMahon Dec 17 '13 at 23:56

2 Answers2

19

To create a regular expression for use later, we use qr//:

my $regexp = qr/^Perl$/;

This compiles the regular expression for use later. If there's a problem with your regular expression, you'll hear about it immediately. To use this pre-compiled regular expression you can use any of the following:

# See if we have a match
$string =~ $regexp;

# A simple substitution
$string =~ s/$regexp/Camel/;

# Comparing against $_
/$regexp/;
alex
  • 1,304
  • 12
  • 15
5

A bare regex literal like /.../ matches agains $_. To create an independent regex object, use qr// quotes:

repeat(qr/foo|bar/i, "y");

(and please don't invoke subs like &sub unless you know when and why this is neccessary.)

amon
  • 57,091
  • 2
  • 89
  • 149
  • When and why is it necessary? – djthoms Dec 17 '13 at 23:51
  • 1
    @djthoms there is a good [overview of the `&` in Perl](http://stackoverflow.com/a/17173958/1521179) by ikegami which mentions the cases (in short, `&sub` is only necessary when disabling a certain feature called “prototypes”, which you aren't even using). – amon Dec 17 '13 at 23:55