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:
build a hash of lists

 



new bie
Novice

Nov 25, 2010, 1:04 AM

Post #1 of 14 (1319 views)
build a hash of lists Can't Post

Hello everyone,

I have a little script below:

opendir (D,"$ENV{HOME}") or die $!;

$count = 0;
foreach $dir (readdir D)
{
$count++;
print "$dir\n" if (-d "$ENV{HOME}/$dir");
}
While this will only print all directory files in current dir, what I want to do is to get all directory files in my tree and build a hash of lists where the keys are directory names and values are the list of subdirs.

Any suggestions on where and how should I start?

thanks for any help,

new bie


rovf
Veteran

Nov 25, 2010, 5:30 AM

Post #2 of 14 (1318 views)
Re: [new bie] build a hash of lists [In reply to] Can't Post

> While this will only print all directory files in current dir

Your code should print all subdirectories of the directory stored in the environment variable HOME, so this would be the "current dir" only if you have chdir'd to this directory.

To go recursively to the subdirectories, I would use the standard module File::Find.


new bie
Novice

Nov 25, 2010, 9:13 AM

Post #3 of 14 (1312 views)
Re: [rovf] build a hash of lists [In reply to] Can't Post

Thanks for replying rovf, I ran the code again and it only prints out subdirs in current $ENV{HOME}, even when I use File::Find. If I want other subdirs, I have to change to $ENV{HOME}/[other dirs here]. Can you tell me what did I do wrong here?

Also, I'm able to build a hash where keys are dir names and values are sizes of those dirs with the codes below:

use File::Find;

find (\&dirsizes, $ENV{HOME});

foreach $dir(sort keys %dirsizes)
{
printf "%-40s: %d\n", $dir, $dirsizes{$dir};
}
sub dirsizes
{
return if !stat;
$dirsizes{$File::Find::dir} += -s;
}

How can I modify this code so I can get keys as my $ENV{HOME} and values as lists of my subdirs? Any suggestions please???

new bie


rovf
Veteran

Nov 26, 2010, 2:04 AM

Post #4 of 14 (1292 views)
Re: [new bie] build a hash of lists [In reply to] Can't Post

It could be that stat fails for certain files in a directory. I would print out $File::Find::dir and $_ just before stat, to see what's going on.


new bie
Novice

Nov 27, 2010, 9:16 PM

Post #5 of 14 (1283 views)
Re: [rovf] build a hash of lists [In reply to] Can't Post

Hi rovf,

I was able to print $File::Find::dir and $_ in the sub as you suggested.
$File::Find::dir #dir names
$_ #dir files under $File::Find::dir

I've tried this in the sub:

$dirfile{$File::Find::dir} = $_;

But this will only return 1 dir file under any $File::Find::dir even if I have more than 1 dir files. I've been trying to get a list of dir files under every $File::Find::dir, but haven't been able to figure it out yet.

For example, let's say my dir tree is like this - dir A and B under ~. I have dir files C and D under A, and E and F under B. I want to list my tree like this:

~=>AB
~/A=>CD
~/B=>EF

Any help is greatly appreciated,

new bie,


FishMonger
Veteran / Moderator

Nov 28, 2010, 7:10 AM

Post #6 of 14 (1278 views)
Re: [new bie] build a hash of lists [In reply to] Can't Post


Code
push @{ $dirfile{$File::Find::dir} }, $_;



new bie
Novice

Nov 28, 2010, 11:45 AM

Post #7 of 14 (1269 views)
Re: [FishMonger] build a hash of lists [In reply to] Can't Post

Thanks for your help FishMonger. However, this code will get a list of $_ in @{$dirfile{$File::Find::dir}} like this:

A
AB
C
CD
E
EF
My tree is like this:
~/AB
~/A/CD
~/B/EF
I'd like to get it like this:
AB
CD
EF
Any suggestions???

Thanks,
new bie


FishMonger
Veteran / Moderator

Nov 28, 2010, 1:26 PM

Post #8 of 14 (1259 views)
Re: [new bie] build a hash of lists [In reply to] Can't Post

I'm not sure I understand what you want to achieve. Do you want a single list/array of all filenames without regard to the directory that they are in, or do you want separate lists/arrays of filenames for each directory?

What I'm suggesting is to use a HoA (Hash of Arrays) where the hash keys are the full directory paths and their values are an array of filenames within that directory.

Here's a working example which I ran on my Windows box.

Code
#!/usr/bin/perl 

use strict;
use warnings;
use File::Find;
use Data::Dumper;

my %dirfile;

find(\&wanted, 'D:/perl');

# Dump the data structure.
print Dumper(\%dirfile), "\n\n";

# now lets output the filenames as is in your last post.
for my $dir ( keys %dirfile ) {
print join("\n", @{ $dirfile{$dir} }), "\n";
}


sub wanted {
return unless -f;
push @{ $dirfile{$File::Find::dir} }, $_;
}


Which outputs:

Code
D:\perl>test.pl 
$VAR1 = {
'D:/perl/Fishmonger' => [
'Example.pm'
],
'D:/perl' => [
'Coder.pm',
'MyConfig.pm',
'perl-1.pl',
'Person.pm',
'test.pl'
],
'D:/perl/users' => [
'ronb.tun'
]
};


Example.pm
Coder.pm
MyConfig.pm
perl-1.pl
Person.pm
test.pl
ronb.tun


Is that what you're looking for?

If not, then please give a more complete description of what you need.


new bie
Novice

Nov 28, 2010, 4:48 PM

Post #9 of 14 (1249 views)
Re: [FishMonger] build a hash of lists [In reply to] Can't Post

Hi FishMonger,

Sorry about the confusion, this is what I need to get:

Let's say my dir tree is like this:
dir file A under ~ (~/A)
dir files B,C,D under A and E under B and F under C (~/A/BCD and ~/A/B/E and ~/A/C/F)

A,B,C,D,E & F all dir files w/text files in them. I need to build a hash of lists where keys are dir names and values are the list of subdirs contained within each of these dirs. Thus the hash should look like this:
~=>A
~/A=>BCD
~/A/B=>E
~/A/C=>F
I'm only able to get:
~=>A
~/A=>D instead of ~/A=>BCD
~/A/B=>E
~/A/C=>F
with this code:

find(\&dirlist, "$ENV{HOME}");
foreach (sort %dirlist)
{
print "$_=>$dirlist{$_}\n";
}
sub dirlist
{
next if !stat or !-d;
next if $_ =~ /^\.|^\../;
$dirlist{$File::Find::dir} = $_;
}

Is it clearer??? I've tried and I've been struggling with it.
I know $_ in the sub are dir files in each of dir and $File::Find::dir are also dir files, but haven't been able to put it together yet.

Any help is greatly appreciated,

new bie


new bie
Novice

Nov 28, 2010, 5:15 PM

Post #10 of 14 (1247 views)
Re: [new bie] build a hash of lists [In reply to] Can't Post

Hi FishMonger,

I think I got it with this code:

find (\&dirfile, "$ENV{HOME}");

foreach (sort %dirfile)
{
print "$_=>@{$dirfile{$File::Find::dir}}\n";
}
sub dirfile
{
next if !stat or !-d;
push @{$dirfile{$File::Find::dir}}, $_;
@{$dirfile{$File::Find::dir}} = sort (@{$dirfile{$File::Find::dir}}; # sort this list
}
Do you see any errors??? I'm able to get what I want in previous post.

Thanks a million, FishMonger.


FishMonger
Veteran / Moderator

Nov 28, 2010, 8:16 PM

Post #11 of 14 (1238 views)
Re: [new bie] build a hash of lists [In reply to] Can't Post

So, based on your last comments, you're saying that don't care about and don't want to track the file names, but instead you only want to track the directory names. Is that right?

Why are you using the stat function that way? In this case, the stat function will always return a true value, so using it the way you are makes no sense.

There's no reason to sort the list until you're ready to output or process that list.


new bie
Novice

Nov 28, 2010, 9:34 PM

Post #12 of 14 (1229 views)
Re: [FishMonger] build a hash of lists [In reply to] Can't Post

That's correct FishMonger. I only want to track directory names. I could get rid of stat and check for -d only. And for sorting the list, just for easy file-tracking.
As you can see, I'm still new to perl, and it's hard to self-learn it. Thanks for all your help.

new bie,


FishMonger
Veteran / Moderator

Nov 29, 2010, 8:07 AM

Post #13 of 14 (1216 views)
Re: [new bie] build a hash of lists [In reply to] Can't Post

Having someone else write the script for you without giving them clear details on what you need does not help either party.

Change:

Code
    return unless -f;


To:

Code
    return unless -d;


Whenever you post your code, always use the code tags as I have done.


new bie
Novice

Nov 29, 2010, 9:52 AM

Post #14 of 14 (1210 views)
Re: [FishMonger] build a hash of lists [In reply to] Can't Post

Hi FishMonger,

I already changed it to return if !-d. And I'll remember to put code tag around codes from now on. I didn't know.

Thanks,

new bie

 
 


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

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