Help requird : got a problem with foreach loop???

V

Vinod. K

Hi everybody,


I have a small query with foreach loop( as well as while loop).
Here is the small script with which i got a problem


----------------------------------------------------

#!/usr/local/perl/5.6.0/bin/perl
my @a=qw/ref txt dat/;
chomp @a;
foreach(@a)
{
my $fl=$_;
if(<*$fl>)
{
chomp $a;
$a=<*$fl>;
print $a,"\n";
}
else
{
print"no files\n";
}
}

-----------------------------------------
O/P of this program(test.pl) :

prompt>test.pl
a.ref
no files

prompt>

--------------------------------------------
Here in the above program, I am trying to list out the files which are
ending with ".ref" or ".txt" or ".dat" extension. But the output I am
getting here is only a file with .ref extension which is first element
of array,@a, even though each one of above said extension files are
existing under a dir from where I ran the this program.

Here .ref is the first element of array,@a. I observed that this
program lists only the files of extension which is there in the first
element of the array,@a and lists only to the maximum of 3 files
eventhough more than 3 files of the same extension are present under
the dirctory. if we change the content of first element to some other
extension, then it will lists files of that extension.


I don't know why it is so??? I am not able understand the logic behind
this foreach loop( and even with while loop too). why it is not
listing files of all the extensions(i.e .dat, .txt, and .ref)???

But if we use unix command, "ls" instead of diamond operator(<>),then
the same above program works fine.

is the probelm with diamond operator or loops???


Please help me out in clearing all my doubts.

Thanks for invaluable time,
- vinod.
 
T

Tad McClellan

Vinod. K said:
Here is the small script with which i got a problem


#!/usr/local/perl/5.6.0/bin/perl
my @a=qw/ref txt dat/;
chomp @a;
foreach(@a)
{
my $fl=$_;
if(<*$fl>)
{
chomp $a;
$a=<*$fl>;
print $a,"\n";
}
else
{
print"no files\n";
}
}


Yes. The problem is your code is not indented to show its structure.

Please help me out in clearing all my doubts.


Please take the time to format your code sensibly if you hope
to get people to volunteer to read it.
 
T

Tad McClellan

Vinod. K said:
I have a small query with foreach loop( as well as while loop).


You problem is not about loops, it is about filename glob()ing.

my @a=qw/ref txt dat/;
chomp @a;


Why are you chomp()ing strings without newlines?

$a=<*$fl>;


Read up on what globbing does when in a scalar context like that.

perldoc -f glob

The glob may return many elements, but your code only looks at
the first one.

Look at the other ones if you want to look at the other ones:

foreach ( <*.$fl> ) {
print "$_\n"
}

Here in the above program, I am trying to list out the files which are
ending with ".ref" or ".txt" or ".dat" extension.

I don't know why it is so???


"Context".

See the section with that same name in perldata.pod.

is the probelm with diamond operator or loops???


That is not the diamond operator, the diamond operator (<>) has
to do with reading input, not with filename globbing.

That is the filename globbing operator (a different way of
writing the glob() function).

Thanks for invaluable time,


Here are some one-liners that do what you are trying to do:

perl -e '$_="*.$_" for @ARGV; print "$_\n" for <@ARGV>' ref txt dat
or
perl -e 'print "$_\n" for glob join " *.", "", @ARGV' ref txt dat
 
A

Anno Siegel

Vinod. K said:
Hi everybody,


I have a small query with foreach loop( as well as while loop).
Here is the small script with which i got a problem

The loop seems to be one part of your program that works.
----------------------------------------------------

#!/usr/local/perl/5.6.0/bin/perl
my @a=qw/ref txt dat/;
chomp @a;
foreach(@a)
{
my $fl=$_;
if(<*$fl>)
{
chomp $a;
$a=<*$fl>;
print $a,"\n";
}
else
{
print"no files\n";
}
}

The lack of indentation makes this just about unreadable. Most people
take that for a reason to skip the post, but let's see what we got.

There is no "strict" and no "warnings". If some code gives you trouble,
switch them on and see if that changes anything.
my @a=qw/ref txt dat/;
chomp @a;

Why chomp @a? There is no way one of the strings could end with a
newline.
foreach(@a) {
my $fl=$_;

If you want a named loop variable, name the loop variable:

foreach my $fl ( @a ) {
if(<*$fl>) {

That glob matches all files that end in "ref" (or "txt", or "dat").
You only want those that end in ".txt" etc. Change the glob to
chomp $a;

Chomping $a before assigning to it is useless. (Warnings would have
warned about it.) Anyway, the glob doesn't append newlines to filenames,
so the chomp is wrong.
$a=<*$fl>;

Here you're doing the glob once again. This isn't necessarily wrong,
but it it wasteful. Do the assignment inside the if-condition.
print $a,"\n";
} else {
print"no files\n";

This prints "no files" for each case ("ref", "txt", and "dat") you're
looping over. This may or may not be what you want.

This it what it boils down to:

use strict; use warnings;
my @a=qw/ref txt dat/;
chomp @a;
foreach(@a) {
my $fl=$_;
if( my $a = <*.$fl>) {
chomp $a;
print "$fl: $a\n";
} else {
print"no files\n";
}
}


However, this will still not work right. You are using glob in scalar
context. This means, you'll get only one file each time through. If
there is more than one file with one of the extensions, you'll miss them.

Using glob in list context, and using it with multiple arguments,
simplifies things:

if ( my @files = <*.ref *.txt *.dat> ) {
print "@files\n";
} else {
print "no files\n";
}


Anno
 
A

Anno Siegel

Vinod. K said:
Hi everybody,


I have a small query with foreach loop( as well as while loop).
Here is the small script with which i got a problem

The loop seems to be one part of your program that works.
----------------------------------------------------

#!/usr/local/perl/5.6.0/bin/perl
my @a=qw/ref txt dat/;
chomp @a;
foreach(@a)
{
my $fl=$_;
if(<*$fl>)
{
chomp $a;
$a=<*$fl>;
print $a,"\n";
}
else
{
print"no files\n";
}
}

The lack of indentation makes this just about unreadable. Most people
take that for a reason to skip the post, but let's see what we got.

There is no "strict" and no "warnings". If some code gives you trouble,
switch them on and see if that changes anything.
my @a=qw/ref txt dat/;
chomp @a;

Why chomp @a? There is no way one of the strings could end with a
newline.
foreach(@a) {
my $fl=$_;

If you want a named loop variable, name the loop variable:

foreach my $fl ( @a ) {
if(<*$fl>) {

That glob matches all files that end in "ref" (or "txt", or "dat").
You only want those that end in ".txt" etc. Change the glob to said:
chomp $a;

Chomping $a before assigning to it is useless. (Warnings would have
warned about it.) Anyway, the glob doesn't append newlines to filenames,
so the chomp is wrong.
$a=<*$fl>;

Here you're doing the glob once again. This isn't necessarily wrong,
but it it wasteful. Do the assignment inside the if-condition.
print $a,"\n";
} else {
print"no files\n";

This prints "no files" for each case ("ref", "txt", and "dat") you're
looping over. This may or may not be what you want.

This it what it boils down to:

use strict; use warnings;
my @a=qw/ref txt dat/;
chomp @a;
foreach(@a) {
my $fl=$_;
if( my $a = <*.$fl>) {
chomp $a;
print "$fl: $a\n";
} else {
print"no files\n";
}
}


However, this will still not work right. You are using glob in scalar
context. This means, you'll get only one file each time through. If
there is more than one file with one of the extensions, you'll miss them.

Using glob in list context, and using it with multiple arguments,
simplifies things:

if ( my @files = <*.ref *.txt *.dat> ) {
print "@files\n";
} else {
print "no files\n";
}


Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top