Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

A strange behavior in File::Find::Rule 3

Status
Not open for further replies.

whn

Programmer
Oct 14, 2007
265
US
Hi, Experts,

At first, please take a look at my code. Please also note that the ONLY difference between RED and BLUE is that @pattern1 has TWO members while @pattern2 has only ONE. Everything else is just the same!!

Code:
#! /usr/bin/perl

use File::Find::Rule;

my $dir = '/sbin';
[COLOR=red]
# Block 1 in RED
my $rule1 =  File::Find::Rule->new;
$rule1->file;
my @pattern1 = ("*power*", "*Power*");
my (@files1);
foreach my $p1 (@pattern1) {
  $rule1->name($p1);
  @files1 = $rule1->in($dir);
}
print "Block 1: \$#files1 = $#files1\n";
if($#files1 > -1) {
  foreach my $f1 (@files1) {
    print "$f1\n";
  }
}[/color]
[COLOR=blue]
# Block 2 in BLUE
my $rule2 =  File::Find::Rule->new;
$rule2->file;
my @pattern2 = ("*power*");
my (@files2);
foreach my $p2 (@pattern2) {
  $rule2->name($p2);
  @files2 = $rule2->in($dir);
}
print "Block 2: \$#files2 = $#files2\n";
if($#files2 > -1) {
  foreach my $f2 (@files2) {
    print "$f2\n";
  }
}[/color]
And here is the output:

Code:
% test.pl
[COLOR=red]Block 1: $#files1 = -1[/color]
[COLOR=blue]Block 2: $#files2 = 5
/sbin/powermig
/sbin/poweroff
/sbin/quick_poweroff
/sbin/powerd
/sbin/powerprotect
/sbin/powermt[/color]

My question: Why does the codes in RED NOT produce the SAME results? How to fix it?

Thank you! This one is driving me nuts.
 
Now I tend to think this is a bug in rule.pm. I used unix 'find' to replace '@files1 = $rule1->in($dir)' and all results came out just as expected.

I have been using this module for quite some time. And now, do I need to go back to replace every occurance with unix 'find'?
 
Try this
Code:
# Block 1 in RED
my $rule1 =  File::Find::Rule->new;
$rule1->file;
my @pattern1 = ("*power*", "*Power*");
my (@files1);
foreach my $p1 (@pattern1) {
  $rule1->name($p1);
  @files1 = $rule1->in($dir);

print "Block 1: \$#files1 = $#files1\n";
if($#files1 > -1) {
  foreach my $f1 (@files1) {
    print "$f1\n";
  }
}
}

@files1 is getting overwritten in your code and never gets a chance to print out. Either push those results into a array or deal with the data before you over write it.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those who say it cannot be done are usually interrupted by someone else doing it; Give the wrong symptoms, get the wrong solutions;
 
Good catch. The problem is that @files is overwritten with each loop of @pattern1. You can do as travs69 showed or you can use push() to keep adding to the @files1 array instead of overwriting it:

Code:
foreach my $p1 (@pattern1) {
  $rule1->name($p1);
  [b]push @files1,$rule1->in($dir);[/b]
}

So the bug is in your code, not in the module.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Thank you, Kevin and Travs!!

Actually, before I posted my codes, I did test Travs's way. I regret I did not mention it. Now I also tried Kevin's way and the output makes me even more believe that the module has a bug.

Here is a piece of code using Travs's way.

Code:
use File::Find::Rule;

my $dir = '/sbin';

# Block 1 in RED[COLOR=red]
my $rule1 =  File::Find::Rule->new;
$rule1->file;
my @pattern1 = ("*power*", "*Power*");
my (@files1);
foreach my $p1 (@pattern1) {
  $rule1->name($p1);
  @files1 = $rule1->in($dir);
  print "Block 1: \$p1 = $p1, \$#files1 = $#files1\n";
  if($#files1 > -1) {
    foreach my $f1 (@files1) {
      print "$f1\n";
    }
  }
}[/color]
print "\n";[COLOR=blue]
# Block 2 in BLUE
my $rule2 =  File::Find::Rule->new;
$rule2->file;
my @pattern2 = ("*power*");
my (@files2);
foreach my $p2 (@pattern2) {
  $rule2->name($p2);
  @files2 = $rule2->in($dir);
  print "Block 2: \$p2 = $p2, \$#files2 = $#files2\n";
  if($#files2 > -2) {
    foreach my $f2 (@files2) {
      print "$f2\n";
    }
  }
}[/color]
print "\n";[b]
# Block 3 in black
my $rule3 =  File::Find::Rule->new;
$rule3->file;
my @pattern3 = ("*Power*", "*power*"); # change the order in @pattern1
my (@files3);
foreach my $p3 (@pattern3) {
  $rule3->name($p3);
  @files3 = $rule3->in($dir);
  print "Block 3: \$p3 = $p3, \$#files3 = $#files3\n";
  if($#files3 > -3) {
    foreach my $f3 (@files3) {
      print "$f3\n";
    }
  }
}[/b]

And here is the output:

Code:
% test1.pl

Block 1: $p1 = *power*, $#files1 = 2
/sbin/poweroff
/sbin/quick_poweroff
/sbin/powerd
Block 1: $p1 = *Power*, $#files1 = -1

Block 2: $p2 = *power*, $#files2 = 2
/sbin/poweroff
/sbin/quick_poweroff
/sbin/powerd

Block 3: $p3 = *Power*, $#files3 = -1
Block 3: $p3 = *power*, $#files3 = -1

Note that bolck 3 returns nothing.
 
And here is a piece of code using Kevin's way.

Code:
use File::Find::Rule;

my $dir = '/sbin';
[COLOR=red]
# Block 1 in RED
my $rule1 =  File::Find::Rule->new;
$rule1->file;
my @pattern1 = ("*power*", "*Power*");
my (@files1);
foreach my $p1 (@pattern1) {
  $rule1->name($p1);
  push @files1, $rule1->in($dir);
}
print "Block 1: \$#files1 = $#files1\n";
if($#files1 > -1) {
  foreach my $f1 (@files1) {
    print "$f1\n";
  }
}[/color]
print "\n";[COLOR=blue]
# Block 2 in BLUE
my $rule2 =  File::Find::Rule->new;
$rule2->file;
my @pattern2 = ("*power*");
my (@files2);
foreach my $p2 (@pattern2) {
  $rule2->name($p2);
  push @files2, $rule2->in($dir);
}
print "Block 2: \$#files2 = $#files2\n";
if($#files2 > -1) {
  foreach my $f2 (@files2) {
    print "$f2\n";
  }
}[/color]
print "\n";[b]
# Block 3 in BLACK
my $rule3 =  File::Find::Rule->new;
$rule3->file;
my @pattern3 = ("*Power*", "*power*"); # changed the order in @pattern1
my (@files3);
foreach my $p3 (@pattern3) {
  $rule3->name($p3);
  push @files3, $rule3->in($dir);
}
print "Block 3: \$#files3 = $#files3\n";
if($#files3 > -1) {
  foreach my $f3 (@files3) {
    print "$f3\n";
  }
}[/b]

And here is the output:
Code:
% test2.pl

Block 1: $#files1 = 2
/sbin/poweroff
/sbin/quick_poweroff
/sbin/powerd

Block 2: $#files2 = 2
/sbin/poweroff
/sbin/quick_poweroff
/sbin/powerd

Block 3: $#files3 = -1

Again, block 3 does not return anything!! Isn't this a bit odd?

Is it because when $rule3->in($dir) finds nothing, it automatically closes the handle $rule3? If so, then it is a bug, I guess.
 
From my reading of the module I think your doing it wrong.. try this
Code:
# Block 3 in BLACK
my $rule3 =  File::Find::Rule->new;
$rule3->file;
my @pattern3 = ('*power*', '*Power*'); # changed the order in @pattern1
my (@files3);
  $rule3->name(@pattern3);
  push @files3, $rule3->in($dir);
print "Block 3: \$#files3 = $#files3\n";
if($#files3 > -1) {
  foreach my $f3 (@files3) {
    print "$f3\n";
  }
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those who say it cannot be done are usually interrupted by someone else doing it; Give the wrong symptoms, get the wrong solutions;
 
Travis,

Do you mean I should single quots instead of double? I also noticed that you changed the array member order back in @pattern3. Is it a typo?

First of all, the sample codes in CPAN used double quots. But I tried it your way, i.e. I used single quots this time. As long as $pattern3[0] is '*Power*' or "*Power*", the codes would not work.
 
I don't think the quotes matter (but you should be using single) but notice I am passing the whole array as to name() instead of looping through the array and calling name over and over.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those who say it cannot be done are usually interrupted by someone else doing it; Give the wrong symptoms, get the wrong solutions;
 
Sorry for not having read your post carefully.

Yes, your way works this time. But how to explan block 1 seemed to work?

Thanks again.
 
Ok, I got it after having read CPAN site again. And actually the cpan site did use single quots!! You're absolutely right, Travis!!

Again, thank you both Travix and Kevin!!
 
I think it only goes through the files once. So Block 1 worked because it found those files. I don't think it would have ever found any capital files though.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those who say it cannot be done are usually interrupted by someone else doing it; Give the wrong symptoms, get the wrong solutions;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top