Beefy Boxes and Bandwidth Generously Provided by pair Networks chromatic writing perl on a camel
go ahead... be a heretic
 
PerlMonks  

globing files with spaces problem.

by Nabuku (Initiate)
on Aug 10, 2002 at 10:08 UTC ( #189163=perlquestion: print w/ replies, xml ) Need Help??
Nabuku has asked for the wisdom of the Perl Monks concerning the following question:

Hi

sorry if this a trivial question, but I'm relatively new to perl...
anyway, here it is:

I'm writing a script what uses directory/files structure to build a multi-level hash. here's the test code I've tried to use:

#!/usr/bin/perl -w use diagnostics; my $source_dir = "/home/haim/tmp/lists"; sub init_source_list { chdir $source_dir or die "Cannot change dir to $source_dir! ($!)"; while (defined($sourcefile = glob("*"))) { # for every file in this # directory if (-d $sourcefile) { # if the file is actually a directory... while (defined($ver = glob("$sourcefile/*"))) { #$ver =~ s/.*\///; #remove everything before the "/". $apps{$sourcefile}{$ver} = undef; # add an empty key to # %apps{$sourcefile} } } else { $apps{$sourcefile} = undef; # add an empty key in the hash # %apps } } } &init_source_list; foreach $key (keys %apps) { if (keys %{ $apps{$key} }) { foreach $vkey (keys %{ $apps{$key} }) { print "$source_dir/$key/$vkey\n"; } } else { print "$source_dir/$key\n"; } }

if there are no spaces in the folders/files names then, everything is ok. the problem starts when one of the directories have spaces. below there are the correct tree and the tree I've got from this script:

Correct:
/home/haim/tmp/lists/png.list
/home/haim/tmp/lists/patches.list
/home/haim/tmp/lists/icon-list
/home/haim/tmp/lists/tcl
/home/haim/tmp/lists/test1
/home/haim/tmp/lists/test2
/home/haim/tmp/lists/test3/ver2
/home/haim/tmp/lists/test3/ver1
/home/haim/tmp/lists/test4
/home/haim/tmp/lists/a b/ver 2
/home/haim/tmp/lists/a b/ver1-default
/home/haim/tmp/lists/test5
/home/haim/tmp/lists/test6/ver2
/home/haim/tmp/lists/test6/ver1
/home/haim/tmp/lists/test7
/home/haim/tmp/lists/packages

The Actual result I've got:
/home/haim/tmp/lists/png.list
/home/haim/tmp/lists/patches.list
/home/haim/tmp/lists/icon-list
/home/haim/tmp/lists/tcl
/home/haim/tmp/lists/test1
/home/haim/tmp/lists/test2
/home/haim/tmp/lists/test3/test3/ver2
/home/haim/tmp/lists/test3/test3/ver1
/home/haim/tmp/lists/test4
/home/haim/tmp/lists/a b/a
/home/haim/tmp/lists/test5
/home/haim/tmp/lists/test6/test6/ver1
/home/haim/tmp/lists/test6/test6/ver2
/home/haim/tmp/lists/test7
/home/haim/tmp/lists/packages

* note the "a b" directory and the test3/test6 directories.

As a workaround I've used 'chdir' to every directory:

sub init_source_list { chdir $source_dir or die "Cannot change dir to $source_dir! ($!)"; while (defined($sourcefile = <*>)) { # for every file in this # directory if (-d $sourcefile) { # if the file is actually a directory... chdir "$sourcefile"; while (defined($ver = <*>)) { $ver =~ s/.*\///; #remove everything before the "/". $apps{$sourcefile}{$ver} = undef; # add an empty key to # %apps{$sourcefile} } chdir "$source_dir"; } else { $apps{$sourcefile} = undef; # add an empty key in the hash # %apps } } }

this one has solved the problem but it's not a very alegant solution.
I was wondering if there is a solution for that (I'm using perl 5.6.1 on both solaris and linux)?

thanx
--
Nabuku

Comment on globing files with spaces problem.
Select or Download Code
Re: globing files with spaces problem.
by atcroft (Monsignor) on Aug 10, 2002 at 12:58 UTC

    More an early morning thought than anything else, but would a solution using opendir(), looping through entries using readdir() looking for the files you need, then closedir(), (such as the example given in the documentation for the readdir() function) resolve the issue?

    Just a thought-hope it might help, and would love to hear when you get it solved.

      thanx.

      you can see below how It was solved.

      --
      Nabuku

Re: globing files with spaces problem.
by kschwab (Priest) on Aug 10, 2002 at 15:26 UTC
    Short Answer: use File::Glob's bsd_glob instead of CORE::glob.

    Long Answer:

    I get the same problem. At first, it appears to be a bug. Supposing the following directory tree:

    /dir1/file1 /dir two/file2
    And the following code:

    foreach my $dir (glob("*")) { foreach my $file (glob("$dir/*")) { print "[$file]\n"; } }
    I get back 'dir' and 'dir1/file1'. Strangely enough, if I use File::Glob's bsd_glob, it works just fine:

    use File::Glob qw(bsd_glob); foreach my $dir (bsd_glob("*")) { foreach my $file (bsd_glob("$dir/*")) { print "file [$file]\n"; } }
    So, I looked at the docs and found that it's working as documented :)

    Since v5.6.0, Perl's CORE::glob() is implemented in terms of bsd_glob(). Note that they don't share the same prototype--CORE::glob() only accepts a single argument. Due to historical reasons, CORE::glob() will also split its argument on whitespace, treating it as multiple patterns, whereas bsd_glob() considers them as one pat tern.

      Hi

      When I've used bsd_glob, I got an endless loop. I'm probably doing something wrong...

      Here's the code I've used:

      #!/usr/bin/perl -w use File::Glob qw(bsd_glob); my $source_dir = "/home/haim/tmp/lists"; sub init_source_list { chdir $source_dir or die "Cannot change dir to $source_dir! ($!)"; while (defined($sourcefile = bsd_glob("*"))) { # for every file in +this # directory if (-d $sourcefile) { # if the file is actually a directory... while (defined($ver = bsd_glob("$sourcefile/*"))) { #$ver =~ s/.*\///; #remove everything before the "/". $apps{$sourcefile}{$ver} = undef; # add an empty key to # %apps{$sourcefile} } } else { $apps{$sourcefile} = undef; # add an empty key in the hash # %apps } } } &init_source_list; foreach $key (keys %apps) { if (keys %{ $apps{$key} }) { foreach $vkey (keys %{ $apps{$key} }) { print "$source_dir/$key/$vkey\n"; } } else { print "$source_dir/$key\n"; } }

      Thanx
      --
      Nabuku

        Change:

        while (defined($sourcefile = bsd_glob("*")))

        to:

        foreach my $sourcefile (bsd_glob("*"))

        bsd_glob doesn't act like the <*.foo> operator, as CORE::glob does.

      Hi folks! I tried with inserting '\' before every space, and it worked!

      foreach my $dir (glob("*")) {
      $dir =~ s/ /\\ /g;
      foreach my $file (glob("$dir/*")) {
      print "$file\n";
      }
      }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://189163]
Approved by wil
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (9)
As of 2014-04-17 04:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (439 votes), past polls