LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Perl syntax and my lack of knowledge. (https://www.linuxquestions.org/questions/programming-9/perl-syntax-and-my-lack-of-knowledge-4175584028/)

jmgibson1981 07-07-2016 02:39 PM

Perl syntax and my lack of knowledge.
 
New job requires me to learn perl. They've given me an assignment to write a little script so here is where i am so far.

Code:

#!/usr/local/bin/perl

use strict;
use warnings;

# patterns

my @patterns = (
                # source
                "",
                # target
                "",
                # reason for failure
                ""
);

# open files

open(INPUT, "<$ARGV[0]");
open(OUTPUT, ">>ARGV[1]");

# main loop

foreach my $patterns (@patterns) {
        while (my $line = <INPUT>) {
                if ($line = $patterns) {
                        print OUTPUT $line;
                }
        }
}

# close files

close(INPUT);
close(OUTPUT);

The goal of this script is to iterate through the patterns array, which will contain regular expressions. then for each of those patterns search through a text file and find it, then assign the found pattern to a variable. finally print a line to a logfile with each found pattern in a certain order.

This is my second day working with perl so I have a long way to go. Like posted, this is what I have so far. Right now I'm having trouble trying to get it to output to the logfile (ARGV[1])

Any guidance or suggestions on methodology would be appreciated.

grail 07-07-2016 03:10 PM

Well I am no perl guru, but I have 2 suggestions:

1. I am not a fan of naming different types of data (in your example scalar and array) with the same name. I do follow that with $ or @ at the start it is kind of clear, but it can get confusing in large scripts to be forced to always look for these (IMHO)

2. Why not start simple and just do the single open for the output and write a single line to it (I am sure there will be millions of returns in your search engine on how to do this)

keefaz 07-07-2016 06:36 PM

There is a typo in OUTPUT, ">>ARGV[1]", should be OUTPUT, ">>$ARGV[1]"

Instead of looping through the patterns and the file lines, just use grep function like

Code:

#!/usr/local/bin/perl

use strict;
use warnings;

# patterns

my @patterns = (
                # source
                'something',
                # target
                'bla$',
                # reason for failure
                '^thing'
);

# open files

open(INPUT, "<$ARGV[0]") or die "$!\n";
open(OUTPUT, ">>$ARGV[1]") or die "$!\n";

# main loop
while (my $line = <INPUT>) {
        print OUTPUT $line if grep {$line =~ /$_/ } @patterns;
}
close INPUT;
close OUTPUT;

Edit, it could be interesting to compile patterns to gain some speed

Straight from example in:
http://perldoc.perl.org/perlop.html#...Like-Operators

Code:

my @patterns = (...);
my @compiled = map qr/$_/, @patterns;

#then use @compiled instead of @patterns with grep

while (my $line = <INPUT>) {
  print OUTPUT $line if grep {$line =~ $_} @compiled;

If patterns list or input text is long, you may better write a match function like in the linked example to avoid unecessary regexp match processing

keefaz 07-08-2016 04:51 AM

Well, I am not satisfied with my grep suggestion. There is no way to stop grep after a match is sucessful, so it continues to check matches through the @patterns/@compiled array even if it founds a match. Grep function does not provide boolean result after all its purpose is to change an array into another.

Just a basic for loop will do, and exit this loop if match is found

Code:

while (<INPUT>) {
    for my $pat(@patterns) {
        print OUTPUT and last if /$pat/;
    }
}


sundialsvcs 07-08-2016 07:27 AM

For instance, foreach my $patterns (@patterns) ... You should not be using the same variable-name here.

Perl is all about various characters such as '$', '@', '%', which are quite powerful but which can have unexpected side-effects. It's actually a tiny language compared to monsters like PHP, because it relies heavily on external modules (use ...).

Also: since you find yourself "in a Perl shop," be sure to ask your co-workers questions freely. Likewise your boss! Perl is a nice language but it has a substantial learning curve at first. Don't feel ashamed to ask "stupid" questions. (The only stupid question is the one you wouldn't ask.)

Take a look at existing source-code. You should be surrounded by it now.

And, while it's okay to ask for help on a forum like this, don't go here for substitutes to the assigned task of confronting the learning-curve yourself. That's what your new employer has tasked you to do ... and, they know that you can and will do it ... and you have the full sympathy and patient understanding of everyone. (There, and certainly here.)

Perl, quirky though it is, has been called "the Swiss ArmyŽ Knife of pragmatic computer programming," and with good reason.

Oh, yeah, one more thing: "meet Tim Toady," if you haven't yet. TMTOWTDI = There's More Than One Way To Do It.™

jmgibson1981 07-08-2016 10:19 AM

I rewrote it for a if / elsif to find the 3 conditions i was looking for. It works now. Just one regex away from putting it into production. Any suggestions on a perl regex to match a line like this?

Code:

From: "Name of Letter" <email@address.com>
Specifically I'd like to extract the email@address field without the leading and trailing <>.

grail 07-08-2016 11:16 AM

You could target the From at the start of the line with anchor and then store the data between the <> with grouping.


All times are GMT -5. The time now is 11:50 AM.