Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Need help with a question.

0 views
Skip to first unread message

Trev

unread,
Jun 28, 2008, 12:33:18 PM6/28/08
to
I'm having a problem with my Perl script, what I would like the script
to achieve is to read a file, search it for certain words, put the
results into an Array so I can then call each result with $var[1] etc
and print output to a file. I tried doing it without Sub routines but
wasn't able to split the results. When I rapped the code into a Sub I
get these errors:

syntax error at test.pl line 7, near "@cpqlog_data"
syntax error at test.pl line 24, near "}"

How come these errors only appear when I use Sub { } ?

test.pl
use English;
use Warnings;

Sub LoadFile
{
open (DAT, "<output.txt") || die("Could not open file!");
@cpqlog_data=<DAT>;

foreach $cpqlog (@cpqlog_data)
{
{
chomp($cpqlog);

if ($cpqlog =~ /MAC/)
{
$cpqlog =~ s/ <FIELD NAME="Subject" VALUE="//i;
$cpqlog =~ s/ <FIELD NAME="MAC" VALUE="//i;
$cpqlog =~ s/"\/>//i;

}
}
}
close DAT;
}

Sub CreateLOG
{
open (BOO, "<blah2.txt");
@lines=<TMP>;
print $lines[1];
close BOO;
}

LoadFile;
CreateLOG;

Gunnar Hjalmarsson

unread,
Jun 28, 2008, 12:45:41 PM6/28/08
to
Trev wrote:
> How come these errors only appear when I use Sub { } ?

Maybe because Perl is case sensitive.

s/Sub/sub/

--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl

Erwin van Koppen

unread,
Jun 28, 2008, 12:45:03 PM6/28/08
to

"Trev" wrote:
>
> How come these errors only appear when I use Sub { } ?

For one thing, you should use lowercase: sub { }

> open (BOO, "<blah2.txt");
> @lines=<TMP>;

You open BOO, but use TMP (which is not opened).

And, you don't check to see of BOO can be opened.

Fix these things, then it should run. However, I doubt it will do what you
want it to do...

Trev

unread,
Jun 28, 2008, 12:56:39 PM6/28/08
to
On Jun 28, 12:45 pm, "Erwin van Koppen" <inva...@invalid.invalid>
wrote:

Thanks, I've made the changes and so far so good.

Erwin van Koppen

unread,
Jun 28, 2008, 1:01:51 PM6/28/08
to

"Trev" wrote:
>
> Thanks, I've made the changes and so far so good.

foreach $cpqlog (@cpqlog_data) {
{
chomp($cpqlog);

if ($cpqlog =~ /MAC/) {
$cpqlog =~ s/ <FIELD NAME="Subject" VALUE="//i;
$cpqlog =~ s/ <FIELD NAME="MAC" VALUE="//i;
$cpqlog =~ s/"\/>//i;
}
}
}

You do understand that the above code does not actually change anything in
the file, right? The substitutions in $cpqlog are just discarded at the end
of the loop.

Oh, and you might want to get rid of the superfluous { }'s...


Dan Mercer

unread,
Jun 28, 2008, 1:02:11 PM6/28/08
to
"Trev" <trevor...@gmail.com> wrote in message
news:b1faad3b-49cb-4fc8...@p25g2000hsf.googlegroups.com...

You're going to feel really dumb. I feel really dumb because it took me 5
minutes to figure out.
Perl is case sensitive. Sub should be sub. In fact, Sub is treated as the
name of a subroutine
which cascades into all sorts of ugliness. Ironically, it's not something
the syntax checker
is good at figuring out. BTW, in CreateLOG you open BOO and read TMP. You
should also
consider "use strict;" which will help you find many syntax errors (just not
this one). You can also
run "perl -c" against your script to just run the compiler pass. I have F4
set to do that in vim
so I can check for syntax errors as I write the code - saves enormous
amounts of time and
energy.

Dan Mercer

Trev

unread,
Jun 28, 2008, 1:12:11 PM6/28/08
to
On Jun 28, 1:01 pm, "Erwin van Koppen" <inva...@invalid.invalid>
wrote:

Yeah, I figured that out, I added a print BOO so the results are
writen to a file which I load in the next sub. This might not be the
best code but I'm still learning.

Ben Morrow

unread,
Jun 28, 2008, 1:40:28 PM6/28/08
to

Quoth Trev <trevor...@gmail.com>:

> I'm having a problem with my Perl script, what I would like the script
> to achieve is to read a file, search it for certain words, put the
> results into an Array so I can then call each result with $var[1] etc
> and print output to a file. I tried doing it without Sub routines but
> wasn't able to split the results. When I rapped the code into a Sub I
> get these errors:
>
> syntax error at test.pl line 7, near "@cpqlog_data"
> syntax error at test.pl line 24, near "}"
>
> How come these errors only appear when I use Sub { } ?
>
> test.pl
> use English;

It's probably a bad idea to get into the habit of using English. Almost
noone who knows Perl well uses it, so you're going to have to learn the
punctation variables anyway; and once you've learned them, it's easier
to remember one list of special cases than two.

> use Warnings;
>
> Sub LoadFile

You've been told 'sub' is case-sensitive; 'warnings' is as well. If
you're on an OS with a case-insensitive filesystem, you need to be
particularly careful about the case of module names: loading a module
with the wrong case can have rather odd effects.

You also want

use strict;

here, and you need to declare your variables with 'my'.

> {
> open (DAT, "<output.txt") || die("Could not open file!");

Since you're just starting to learn Perl now, you *definitely* want to
get into the habit of using lexical filehandles right away; that is,
instead of 'DAT', use a real variable. You also want to use three-arg
open, and give the reason why the open failed:

open (my $DAT, '<', 'output.txt')
|| die("Could not open 'output.txt': $!");

I would use 'or' instead of '||', and omit the parens, but that's
entirely up to you.

> @cpqlog_data=<DAT>;
>
> foreach $cpqlog (@cpqlog_data)

This is not the most straightforward way to read a file. Since you're
processing it entirely line-by-line, read it line-by-line as well.

while (my $cpqlog = <$DAT>) {

> {

If you use GNUish indenting, and such a large indent, you'll quickly run
out of screen room... :)

> close DAT;

One of the advantages of lexical filehandles is that they close
themselves when they go out of scope. If you're not going to check the
return value of close (not generally necessary when reading a file),
it's much more convenient to omit it.

Once you've got the syntax errors sorted out, I presume you can start
working out the logic errors on your own... :) Don't be afraid to ask
again if you get stuck.

Ben

--
We do not stop playing because we grow old;
we grow old because we stop playing.
b...@morrow.me.uk

Trev

unread,
Jun 28, 2008, 4:18:08 PM6/28/08
to
On Jun 28, 1:40 pm, Ben Morrow <b...@morrow.me.uk> wrote:
Thanks Ben for the detailed reply, I've been able to get the output
correct, but I'm stuck on how to read $cpqlogline into an array
without writing it to a file.

my files look like this:

the perl file:

use warnings;
use strict;

my $server_file = "list.txt";
my $mactmp = "mactmp.txt";
my $maclog = "logfile.txt";

sub LoadFile
{
open(my $SRV, '<', $server_file)
or die("Could not open file: $!");

while (my $server = <$SRV>) {
chomp($server);


open (my $DAT, '<', 'output.txt')
|| die("Could not open 'output.txt': $!");

open (OTF, ">blah.txt");
print OTF $DAT;

while (my $cpqlogline = <$DAT>) {
{
chomp($cpqlogline);
if ($cpqlogline =~ /MAC/)
{
$cpqlogline =~ s/ <FIELD NAME="Subject" VALUE="//i;
$cpqlogline =~ s/ <FIELD NAME="MAC" VALUE="//i;
$cpqlogline =~ s/"\/>//i;

open (TMP, ">>$mactmp");
print TMP "$server". "," . "$cpqlogline\n";
close TMP;
}
}
}
}
close OTF;
}

sub CreateLOG
{
open (TMP, "<$mactmp");
open (LOG, ">>$maclog");
my @lines=<TMP>;
print LOG "$lines[1]";
close TMP;
close LOG;
print @lines;


unlink "blah.txt";
#unlink $mactmp;
}

LoadFile;
CreateLOG;

The list.txt file:

server1
server2
server3

The output.txt file:

<FIELD NAME="Subject" VALUE="Embedded NIC MAC Assignment"/>
<FIELD NAME="Port" VALUE="1"/>
<FIELD NAME="MAC" VALUE="00-00-00-00-00-01"/>
<FIELD NAME="Port" VALUE="2"/>
<FIELD NAME="MAC" VALUE="00-00-00-00-00-02"/>
<FIELD NAME="Port" VALUE="iLO"/>
<FIELD NAME="MAC" VALUE="00-00-00-00-00-03"/>

When the script runs it only creats the logfile with one line:
server1,00-00-00-00-00-01

When it should show:
server1,00-00-00-00-00-01
server2,00-00-00-00-00-01
server3,00-00-00-00-00-01

I see the problem is that the CreateLog only reads value[1] since the
above sub writes everything into mactmp.txt then only CreateLog is
run.

Any ideas?

Jürgen Exner

unread,
Jun 28, 2008, 4:36:08 PM6/28/08
to
Trev <trevor...@gmail.com> wrote:
>On Jun 28, 1:40 pm, Ben Morrow <b...@morrow.me.uk> wrote:
>Thanks Ben for the detailed reply, I've been able to get the output
>correct, but I'm stuck on how to read $cpqlogline into an array
>without writing it to a file.

I suppose with "read into an array" you meant storing the value in an
array. Please see e.g. "perldoc -f push".

However, there is no need for that. Why not write the output file line
by line simultaneously as you process the input file line by line?

jue

Anonymous coward

unread,
Jun 28, 2008, 5:00:33 PM6/28/08
to
On Sat, 28 Jun 2008 13:18:08 -0700, Trev wrote:

> On Jun 28, 1:40 pm, Ben Morrow <b...@morrow.me.uk> wrote: Thanks Ben for
> the detailed reply, I've been able to get the output correct, but I'm
> stuck on how to read $cpqlogline into an array without writing it to a
> file.
>

push @array, $cpqlogline;

> open (OTF, ">blah.txt");
> print OTF $DAT;

That makes no sense at all. Why would you want to print a filehandle

> $cpqlogline =~ s/ <FIELD NAME="Subject" VALUE="//i;
> $cpqlogline =~ s/ <FIELD NAME="MAC" VALUE="//i;
> $cpqlogline =~ s/"\/>//i;

Can't you do that in a more robust manner? XML::Simple is your friend. Or
a single m// regexp if you are certain the order of the attributes is
always the same.

> open (TMP, ">>$mactmp");
> print TMP "$server". "," . "$cpqlogline\n"; close TMP;

Why do you open and close a file inside a loop? Why don't you just say
print "$server,$cpglogline\n" ?

> }
> close OTF;

You might want to close that in the same block as where you opened it.

> print LOG "$lines[1]";

What do the quotes serve for?

> unlink "blah.txt";

Why unlink that here?


> When the script runs it only creats the logfile with one line:
> server1,00-00-00-00-00-01
>
> When it should show:
> server1,00-00-00-00-00-01
> server2,00-00-00-00-00-01
> server3,00-00-00-00-00-01
>
> I see the problem is that the CreateLog only reads value[1] since the
> above sub writes everything into mactmp.txt then only CreateLog is run.
>
> Any ideas?

This program makes absolutely no sense to me. What are you trying to do
exactly? Can you give a bit more description?

Cheers,

Leon

Jürgen Exner

unread,
Jun 28, 2008, 5:33:49 PM6/28/08
to
Anonymous coward <anon...@cow.ard> wrote:
>On Sat, 28 Jun 2008 13:18:08 -0700, Trev wrote:
>> open (OTF, ">blah.txt");
>> print OTF $DAT;
>
>That makes no sense at all. Why would you want to print a filehandle

Maybe he wants to print _to_ a filehandle?

>> open (TMP, ">>$mactmp");
>> print TMP "$server". "," . "$cpqlogline\n"; close TMP;
>
>Why do you open and close a file inside a loop?

Indeed, that is an expensive operation that is better done once outside
of the loop.

>Why don't you just say
>print "$server,$cpglogline\n" ?

Mabye because (unless you set the default filehandle using select()) the
text will end up on the screen instead of in the file?

>This program makes absolutely no sense to me. What are you trying to do
>exactly? Can you give a bit more description?

It is certainly somewhat cryptic.

jue

Trev

unread,
Jun 28, 2008, 5:44:35 PM6/28/08
to
On Jun 28, 5:33 pm, J�rgen Exner <jurge...@hotmail.com> wrote:

I'm connecting to many servers extracting XML data to a file, I then
only want the MAC address of Port 1 for each server. The part where I
open an existing file (output.txt) and dump content into blah.txt is
for testing, once the script it working I will remove that portion as
the output.txt file will be different for each server.

Hope that helps. I'll look into the push.

Thanks

Leon Timmermans

unread,
Jun 28, 2008, 6:10:53 PM6/28/08
to
On Sat, 28 Jun 2008 21:33:49 +0000, Jürgen Exner wrote:

>>Why don't you just say
>>print "$server,$cpglogline\n" ?
>
> Mabye because (unless you set the default filehandle using select()) the
> text will end up on the screen instead of in the file?

Oops, that was a typo on my part. I wanted to say print TMP "$server,
$cpglogline\n".

Leon

Ben Morrow

unread,
Jun 28, 2008, 6:22:08 PM6/28/08
to

Quoth Trev <trevor...@gmail.com>:

> On Jun 28, 1:40 pm, Ben Morrow <b...@morrow.me.uk> wrote:
> Thanks Ben for the detailed reply, I've been able to get the output
> correct, but I'm stuck on how to read $cpqlogline into an array
> without writing it to a file.
>
> my files look like this:
>
> the perl file:
>
> use warnings;
> use strict;
>
> my $server_file = "list.txt";
> my $mactmp = "mactmp.txt";
> my $maclog = "logfile.txt";
>
> sub LoadFile
> {
> open(my $SRV, '<', $server_file)
> or die("Could not open file: $!");
>
> while (my $server = <$SRV>) {
> chomp($server);
> open (my $DAT, '<', 'output.txt')
> || die("Could not open 'output.txt': $!");

If you reopen output.txt every time you will start at the beginning
again.

> open (OTF, ">blah.txt");
> print OTF $DAT;

What are you trying to achieve here? You don't ever seem to make use of
the contents of blah.txt.

> while (my $cpqlogline = <$DAT>) {
> {
> chomp($cpqlogline);
> if ($cpqlogline =~ /MAC/)
> {
> $cpqlogline =~ s/ <FIELD NAME="Subject" VALUE="//i;
> $cpqlogline =~ s/ <FIELD NAME="MAC" VALUE="//i;
> $cpqlogline =~ s/"\/>//i;
>
> open (TMP, ">>$mactmp");
> print TMP "$server". "," . "$cpqlogline\n";
> close TMP;

You don't need to keep everything in temporary files like this. Perl has
variables for keeping data in.

Here you write all the data into mactmp.txt; in fact, you write a line
for every server with every mac address. I don't think this is what you
meant.

> }
> }
> }
> }
> close OTF;
> }
>
> sub CreateLOG
> {
> open (TMP, "<$mactmp");
> open (LOG, ">>$maclog");
> my @lines=<TMP>;
> print LOG "$lines[1]";

Here you reopen mactmp.txt, read all the data into @lines, print the
second line (only) to maclog.txt, and throw the rest away. This is why
you only get one record in the log at the end.

I'm not quite sure how to help you at this point. You seem to be missing
several rather fundamental points about how Perl works. If I were
writing this program, I might write it something like this (completely
untested):

#!/usr/bin/perl

my $srvs = 'list.txt';
my $macs = 'output.txt';
my $log = 'logfile.txt';

# Only open each file once. We don't need any temporary files.
open my $SRVS, '<', $srvs or die "can't read '$srvs': $!";
open my $MACS, '<', $macs or die "can't read '$macs': $!";
open my $LOG, '>>', $log or die "can't append to '$log': $!";

# For each line in output.txt...
while (<$MACS>) {

# if it matches the pattern, put the VALUE field in $mac...
my ($mac) = /<FIELD NAME="MAC" VALUE="([^"]+)">/
# otherwise move on to the next line.
or next;

# Get the next server from the list.
my $srv = <$SRVS> or die "Not enough servers.\n";
chomp $srv;

# Write a line to the logfile.
print $LOG "$srv,$mac\n";
}

# Close the logfile explicitly so we can check all the data got
# written safely.
close $LOG or die "writing to '$log' failed: $!";

# Check if there are any servers left.
<$SRVS> and die "Not enough addresses.\n";

__END__

Can you understand what that's doing?

Trev

unread,
Jun 28, 2008, 10:07:21 PM6/28/08
to
On Jun 28, 6:22 pm, Ben Morrow <b...@morrow.me.uk> wrote:
> Quoth Trev <trevor.do...@gmail.com>:

Hi

I'm only after 1 line (MAC) per server, which is value [1] the other
MAC's I do not need. Is it possible to grep MAC from the Array (Entire
File) and pass the results into a new array which I could then
print[1] to a file. This will then extract 1 line for every server
that I have an xml file for.

Trev

unread,
Jun 29, 2008, 7:25:05 AM6/29/08
to

>
> I'm only after 1 line (MAC) per server, which is value [1] the other
> MAC's I do not need. Is it possible to grep MAC from the Array (Entire
> File) and pass the results into a new array which I could then
> print[1] to a file. This will then extract 1 line for every server
> that I have an xml file for.

Maybe this will help...

Read list.txt for each server listed do
read xml file into array
find results matching MAC
print the 1st MAC address only ($server,$mac[1])
go back to list.txt and do the same for next server listed in file.

That's what I'm trying to do with this perl script.

Dr.Ruud

unread,
Jun 29, 2008, 8:01:30 AM6/29/08
to
Trev schreef:

> Subject: Need help with a question.

That is not a proper Subject. Read the Posting Guidelines, as they are
posted in this group about twice a week.

--
Affijn, Ruud

"Gewoon is een tijger."

Ben Morrow

unread,
Jun 29, 2008, 1:45:33 PM6/29/08
to

Quoth Trev <trevor...@gmail.com>:

>
> >
> > I'm only after 1 line (MAC) per server, which is value [1] the other
> > MAC's I do not need. Is it possible to grep MAC from the Array (Entire
> > File) and pass the results into a new array which I could then
> > print[1] to a file. This will then extract 1 line for every server
> > that I have an xml file for.
>
> Maybe this will help...
>
> Read list.txt for each server listed do
> read xml file into array
> find results matching MAC
> print the 1st MAC address only ($server,$mac[1])

Index [1] is the second item in an array. You need to go read a decent
beginner's Perl book: see perldoc -q book.

Ben

--
It will be seen that the Erwhonians are a meek and long-suffering people,
easily led by the nose, and quick to offer up common sense at the shrine of
logic, when a philosopher convinces them that their institutions are not based
on the strictest morality. [Samuel Butler, paraphrased] b...@morrow.me.uk

Jim Gibson

unread,
Jun 30, 2008, 11:27:11 AM6/30/08
to
In article <48666e7f$0$14348$e4fe...@news.xs4all.nl>, Erwin van Koppen
<inv...@invalid.invalid> wrote:

> "Trev" wrote:
> >
> > Thanks, I've made the changes and so far so good.
>
> foreach $cpqlog (@cpqlog_data) {
> {
> chomp($cpqlog);
>
> if ($cpqlog =~ /MAC/) {
> $cpqlog =~ s/ <FIELD NAME="Subject" VALUE="//i;
> $cpqlog =~ s/ <FIELD NAME="MAC" VALUE="//i;
> $cpqlog =~ s/"\/>//i;
> }
> }
> }
>
> You do understand that the above code does not actually change anything in
> the file, right? The substitutions in $cpqlog are just discarded at the end
> of the loop.

Not quite. In Perl, the loop variable $cpqlog is an "alias" to the
array elements, so the changes to $cpqlog are applied to the members of
the array. Of course, whether or not the file is modified depends upon
what is done after the loop. (Just trying to clear up any
misunderstanding about what "discarded at the end of the loop" means.)

--
Jim Gibson

J. Gleixner

unread,
Jun 30, 2008, 12:13:34 PM6/30/08
to

Since you're parsing an XML file, possibly using XML::Simple
will make it much easier.

http://search.cpan.org/~grantm/XML-Simple-2.18/lib/XML/Simple.pm

Hans Mulder

unread,
Jun 30, 2008, 9:27:35 PM6/30/08
to
Erwin van Koppen wrote:
> "Trev" wrote:
>> Thanks, I've made the changes and so far so good.
>
> foreach $cpqlog (@cpqlog_data) {
> {
> chomp($cpqlog);

It's more efficient to chomp the whole array before the start of the loop:
chomp(@cpqlog_data);

> if ($cpqlog =~ /MAC/) {
> $cpqlog =~ s/ <FIELD NAME="Subject" VALUE="//i;
> $cpqlog =~ s/ <FIELD NAME="MAC" VALUE="//i;
> $cpqlog =~ s/"\/>//i;
> }
> }
> }
>
> You do understand that the above code does not actually change anything in
> the file, right? The substitutions in $cpqlog are just discarded at the end
> of the loop.

No they're not: this code is changing the @cpqlog_data array.

You'd still have to write that array back to the file if that's the
intent.

> Oh, and you might want to get rid of the superfluous { }'s...

Or else, change the indentation to reflect the extra {}'s:

chomp(@cpqlog_data);

foreach my $cpqlog (@cpqlog_data)
{
{


if ($cpqlog =~ /MAC/)
{
$cpqlog =~ s/ <FIELD NAME="Subject" VALUE="//i;
$cpqlog =~ s/ <FIELD NAME="MAC" VALUE="//i;
$cpqlog =~ s/"\/>//i;
}
}
}

Or maybe use the magic $_ variable:

chomp(@cpqlog_data);

foreach (@cpqlog_data) {
if (/MAC/) {


s/ <FIELD NAME="Subject" VALUE="//i;

s/ <FIELD NAME="MAC" VALUE="//i;

s|"/>||i;
}
}

Hope this helps,

-- HansM

0 new messages