CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Trying to make an indexer in perl

 



Beastie
Novice

Apr 8, 2009, 3:35 PM

Post #1 of 16 (2532 views)
Trying to make an indexer in perl Can't Post

I'm trying to write an indexer in perl. I'm running Debian. This script is doing squat. Is it because the condition a little ways down is evaluating positive all the time? It should still print to the file, though, so I don't get it. I was messing around trying to chomp off the newlines in the elements of @subdirs (I tried doing it a few different ways just to make sure that wasn't the problem) just before I gave up in frustration, so if that bit of the code is weird, that's why.

Also, the beginning is just getting everything that SHOULD be in the index after this thing works and sticking it in a string, but the file is empty right now so it doesn't do anything.

Help!

Code:
____________

$path="/PFILES/indexer/INDEX";
@index=();
open (OUTFILE , $path);
while (<OUTFILE>){
push(@index , $_);
}
$wholeindex=join(/ / , @index);
close (OUTFILE);
open (OUTFILE , ">>$path");
@subdirs=`ls /`;
$c=$#subdirs;
while ($c>=0){
chomp($subdirs[$c]);
$c=$c-1;
}
foreach (@subdirs){
shift(@subdirs);
$_=("/" . $_);
if ($_!~/$wholeindex/){
print OUTFILE "$_\n";
my @lowerdirs=`ls $_`;
if ($lowerdirs!~"$_"){
foreach my $lowerdirs (@lowerdirs){
push(@subdirs , $lowerdirs);

}
}
@lowerdirs=();
}
}
_____________


KevinR
Veteran


Apr 8, 2009, 9:06 PM

Post #2 of 16 (2525 views)
Re: [Beastie] Trying to make an indexer in perl [In reply to] Can't Post

Very strange code. You seem to have a fundamental lack of understanding of perl. I would toss all that code and start over. When you say an "indexer" what does that mean? Just listing files in a directory?
-------------------------------------------------


Beastie
Novice

Apr 9, 2009, 5:49 AM

Post #3 of 16 (2518 views)
Re: [Beastie] Trying to make an indexer in perl [In reply to] Can't Post

Did I do anything Perl doesn't let me do?

Am I not allowed to add elements to the array I'm iterating over with a foreach? The point of doing this was to avoid having it need to remember the names of every directory/file it has already written as well as the names of those it is finding in lower directories. I was trying to add elements to the front of the array, though... does foreach not like it when I do that?

I was writing this as an exercise in perl. It was simply meant to write the path of everything in the filesystem to a file called INDEX, separated by newlines.


FishMonger
Veteran / Moderator

Apr 9, 2009, 7:11 AM

Post #4 of 16 (2514 views)
Re: [Beastie] Trying to make an indexer in perl [In reply to] Can't Post


Quote
It was simply meant to write the path of everything in the filesystem to a file called INDEX, separated by newlines.


This will satisify that requirement.

Code
find / > /PFILES/indexer/INDEX



Beastie
Novice

Apr 10, 2009, 10:02 AM

Post #5 of 16 (2495 views)
Re: [FishMonger] Trying to make an indexer in perl [In reply to] Can't Post

This will satisify that requirement.

Code
find / > /PFILES/indexer/INDEX



That's exactly what I was trying to avoid using. I don't want to do it using recursion. That's why I didn't use that.


Beastie
Novice

Apr 10, 2009, 12:20 PM

Post #6 of 16 (2490 views)
umm... [In reply to] Can't Post


Code
#!usr/bin/perl-w 

$path="/PFILES/indexer/INDEX";
@index=();
open (OUTFILE , $path);
while (<OUTFILE>){
push(@index , $_);
}
$wholeindex=join(/ / , @index);
close (OUTFILE);
open (OUTFILE , ">>$path");
@subdirs=`ls /`;
$c=$#subdirs;
while ($c>=0){
chomp($subdirs[$c]);
$c=$c-1;
}
$i=0;

while ($i<=$#subdirs){
$subdirs[$i]="/".$subdirs[$i];
if ($subdirs[$i]!="/proc"){splice(@subdirs,$i,1);$i--;next}
if ($subdirs[$i]!="/sys"){splice(@subdirs,$i,1);$i--;next}
$i+=1;
}
foreach (@subdirs){
shift(@subdirs);
chomp($_);


print OUTFILE "$_\n";
my @lowerdirs=`ls $_`;

foreach my $lowerdirs (@lowerdirs){
chomp($lowerdirs);
if ($lowerdirs!~/$_/){
push(@subdirs , $_."/".$lowerdirs."/");
}
}

@lowerdirs=();
}
}


Updated code... It's doing stuff. It's having some issues, though... Here's a sample of the error bash is giving me:
"ls: cannot access /etc/sane.d//avision.conf/: Not a directory"
It's getting there, though.... what's going on? Any idea?


KevinR
Veteran


Apr 10, 2009, 2:02 PM

Post #7 of 16 (2483 views)
Re: [Beastie] umm... [In reply to] Can't Post

Like I said before, you seem to have a lack of the fundamentals of perl, your code is very tortured to do simple things, but I can't teach you perl. These lines are certainly wrong:

if ($subdirs[$i]!="/proc")

!= is used for comparing numbers, not strings. Since you are running perl with the -w switch you should be getting warnings associated with those lines. Try this simple test:


Code
use warnings; 
$foo = 'bar';
if ($foo != 'blah') {
print "Foo!";
}


Argument "blah" isn't numeric in numeric ne (!=) at script line 3.
Argument "bar" isn't numeric in numeric ne (!=) at script line 3.

Then look up perls string comparison operators:

eq
ne
gt
lt
cmp
-------------------------------------------------


(This post was edited by KevinR on Apr 10, 2009, 2:03 PM)


Beastie
Novice

Apr 10, 2009, 9:43 PM

Post #8 of 16 (2475 views)
Re: [KevinR] umm... [In reply to] Can't Post

Yes, I had seen those operators, but I hadn't realized that they was actually a difference between "==" and "eq".

I've already fixed this, because a friend noticed and informed me. I also changed a few other things, and it now works perfectly.

Part of the reason it is "tortured"... is there something that edits each element of an array? (Those while loops are now the same loop, by the way. They were only separate because I added them at different times.) Also, can you tell me some parts of the code could be fixed so as to be less "tortured"? It's clear I do not know perl that well, and tips are welcome.


KevinR
Veteran


Apr 10, 2009, 11:34 PM

Post #9 of 16 (2473 views)
Re: [Beastie] umm... [In reply to] Can't Post

Lets look at this section of code:


Code
#!usr/bin/perl-w  

$path="/PFILES/indexer/INDEX";
@index=();
open (OUTFILE , $path);
while (<OUTFILE>){
push(@index , $_);
}
$wholeindex=join(/ / , @index);
close (OUTFILE);
open (OUTFILE , ">>$path");
@subdirs=`ls /`;
$c=$#subdirs;
while ($c>=0){
chomp($subdirs[$c]);
$c=$c-1;
}


The one section that is really tortured is the chomping, here is that section rewrote, note how easy it is to chomp all elements of an array:


Code
#!/usr/bin/perl 
use warnings;
use strict;

my $path="/PFILES/indexer/INDEX";
open (my $OUTFILE , "<", $path) or die "$!";
my $wholeindex = do{local $/; <$OUTFILE>}; #read file into a scalar
close ($OUTFILE);

my @subdirs = grep {!/proc|sys/} `ls /`; #get all dirs except proc and sys

chomp(@subdirs); #chomp each element of @subdirs


I think this one line in my code:


Code
my @subdirs = grep {!/proc|sys/} `ls /`; #get all dirs except proc and sys


replaces all of this section of your code:


Code
while ($i<=$#subdirs){  
$subdirs[$i]="/".$subdirs[$i];
if ($subdirs[$i]!="/proc"){splice(@subdirs,$i,1);$i--;next}
if ($subdirs[$i]!="/sys"){splice(@subdirs,$i,1);$i--;next}
$i+=1;
}


I assume you are trying to remove proc and sys from the array.

This is almost assuredly wrong:


Code
foreach (@subdirs){  
shift(@subdirs);


If you just want to loop through all the elements of an array automatically the "foreach" control does that. I am not sure why you put shift() in there.
-------------------------------------------------


(This post was edited by KevinR on Apr 10, 2009, 11:45 PM)


Beastie
Novice

Apr 11, 2009, 7:11 AM

Post #10 of 16 (2459 views)
Re: [KevinR] umm... [In reply to] Can't Post

Yes, but where do you add in the "/" before the names of the directories under root? I just didn't see any other way to do that except a loop.

Shift removes the first element of an array. This isn't a big deal, because that element is in $_, so I can still use it, but there is no need to keep storing it after that point.


Beastie
Novice

Apr 11, 2009, 7:13 AM

Post #11 of 16 (2458 views)
Re: [KevinR] umm... [In reply to] Can't Post

Wow, I really like that "chomp(@subdirs)" line. I didn't realize chomp allowed you to give it an array; that is very cool.


KevinR
Veteran


Apr 11, 2009, 9:12 AM

Post #12 of 16 (2452 views)
Re: [Beastie] umm... [In reply to] Can't Post


Quote
Yes, but where do you add in the "/" before the names of the directories under root? I just didn't see any other way to do that except a loop.


If you have an array and wanted to add a / to the front of each element:


Code
$_ = "/$_" for @arrray;



Quote
Shift removes the first element of an array. This isn't a big deal, because that element is in $_, so I can still use it, but there is no need to keep storing it after that point.


Lets look at what happens


Code
@array = (1 .. 10); 

foreach (@array) {
shift(@array);
print;
}


Note what gets printed: 13579
-------------------------------------------------


(This post was edited by KevinR on Apr 11, 2009, 9:12 AM)


Beastie
Novice

Apr 11, 2009, 9:45 AM

Post #13 of 16 (2449 views)
Re: [KevinR] umm... [In reply to] Can't Post

http://perldoc.perl.org/functions/shift.html

That's from perldoc (self-evident, but whatever).
Shift does precisely what perldoc describes, but... well, let me reason through this. When you shift(@array), you remove the first element ([0]). When you printed in the example, you were printing $_, which is what element zero was the first time through; for this reason, the first output is 1. But now, the array contains 2..10, two being in element zero. Does foreach go through the elements of the array 0,1,2,3,4 no matter whether or not these elements contain the same values? I guess it does, which would explain your output. Huh. That means I'm only getting half of my output. I hadn't thought of that. How should I account for that? Should I do this?:

Code
$i=0; 
while (@subdirs[$i]){stuff}



KevinR
Veteran


Apr 11, 2009, 11:02 AM

Post #14 of 16 (2445 views)
Re: [Beastie] umm... [In reply to] Can't Post

shift() is destructive because it removes the element from the array and the rest of the elements are all shifted accordingly. To just loop through all the elements of an array you use "for" or "foreach".

for/foreach loops through all the elements of an array regardless of their values. You can see exactly what is going on by printing the various elements during the loop:


Code
@array = (1..10); 
for (@array) {
print "the current array is: @array\n";
print "We are shifting off element: ", shift(@array), "\n";
print "Current value of \$_: $_\n";

}


The output will probably confuse you:

the current array is: 1 2 3 4 5 6 7 8 9 10
We are shifting off element: 1
Current value of $_: 1
the current array is: 2 3 4 5 6 7 8 9 10
We are shifting off element: 2
Current value of $_: 3
the current array is: 3 4 5 6 7 8 9 10
We are shifting off element: 3
Current value of $_: 5
the current array is: 4 5 6 7 8 9 10
We are shifting off element: 4
Current value of $_: 7
the current array is: 5 6 7 8 9 10
We are shifting off element: 5
Current value of $_: 9


I must admit it confuses me too. But it shows you should not be looping through the array and shifting off the first element in the loop. There might be situations where that is required, but I can't think of one off the top of my head.
-------------------------------------------------


Beastie
Novice

Apr 11, 2009, 2:17 PM

Post #15 of 16 (2443 views)
Re: [KevinR] umm... [In reply to] Can't Post

It looks like it just counts up from zero when assigning to $_.

The reason I'm taking off the first element is simply so that the loop doesn't act on that element again. If I didn't and I put a bunch more elements in before an element (which is what happens; the way it works is it's going to print a parent directory and then take all of the directories/files below it and put them in the beginning of the array) it would be an infinite loop because it would keep acting on that same element... the point being that this is an instance in which shifting off an element is necessary.

Again, would the code I posted last time be a good substitute for the foreach loop I currently have?


KevinR
Veteran


Apr 11, 2009, 4:10 PM

Post #16 of 16 (2440 views)
Re: [Beastie] umm... [In reply to] Can't Post


In Reply To
The reason I'm taking off the first element is simply so that the loop doesn't act on that element again. If I didn't and I put a bunch more elements in before an element (which is what happens; the way it works is it's going to print a parent directory and then take all of the directories/files below it and put them in the beginning of the array) it would be an infinite loop because it would keep acting on that same element... the point being that this is an instance in which shifting off an element is necessary.

Again, would the code I posted last time be a good substitute for the foreach loop I currently have?


I am having a hard time following your description but I doubt shifting the array while looping through the array is the correct way to do whatever it is you are doing. In the "foreach" loop you posted previously, you are never adding elements into the array before an element, you are using push() which adds them to the end of the array regardless of where you are in the current loop (the first loop):


Code
foreach (@subdirs){  
shift(@subdirs);
chomp($_);


print OUTFILE "$_\n";
my @lowerdirs=`ls $_`;

foreach my $lowerdirs (@lowerdirs){
chomp($lowerdirs);
if ($lowerdirs!~/$_/){
push(@subdirs , $_."/".$lowerdirs."/");
}
}

@lowerdirs=();
}
}


What you might really want, if you continue with this excersize, is to use an array of arrays.
-------------------------------------------------

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives