Selecting directories containing specific fileglobs

E

Eden Cardim

Hello everyone,

I'm developing a system using mod_perl and the Maypole module, and I've
come across an annoying problem. I want to select the first
subdirectory inside another directory that contains files ending with
'.esd'. I've tried the following code but it doesn't work, it selects
empty subdirectories as well:

my($dir) = grep { -d $_ && <$_/*.esd> } glob($self->inputFolder .
'/*');

$self->inputFolder always returns a full path to the base directory
where I want the selection to be done.
This always works on a one-liner, but sometimes it doesn't when used in
mod_perl. Any suggestions on what could be causing this?
Thanks in advance.
 
B

Brian McCauley

Eden said:
I want to select the first
subdirectory inside another directory that contains files ending with
'.esd'. I've tried the following code but it doesn't work, it selects
empty subdirectories as well:

my($dir) = grep { -d $_ && <$_/*.esd> } glob($self->inputFolder .
'/*');

$self->inputFolder always returns a full path to the base directory
where I want the selection to be done.
This always works on a one-liner, but sometimes it doesn't when used in
mod_perl. Any suggestions on what could be causing this?

glob() (or <...> used as glob() ) in a scalar context has weird magical
memory attached to where it is called from.

Consider

print scalar <foo*>,scalar <bar*>;

print scalar <$_*> for 'foo','bar';

You may expect both of these to print the first file starting foo then
the first starting bar.

Actully the second prints the first two starting foo because the scalar
context glob function remembers that it's got a list of files starting
foo to return and will not re-examine it's argument until it has done
that.

You need to force a list context on glob().

my($dir) = grep { -d $_ && @{[<$_/*.esd>]} } glob($self->inputFolder
..'/*');

my($dir) = grep { -d $_ && (()=<$_/*.esd>) } glob($self->inputFolder
..'/*');

BTW: I tend to avoid using the <...> notation for glob().
 
E

Eden Cardim

Actully the second prints the first two starting foo because the scalar
context glob function remembers that it's got a list of files starting
foo to return and will not re-examine it's argument until it has done
that.

Interesting, the documentation doesn't mention this.
Thanks, it seems to be working now.
 
B

Brian McCauley

Eden said:
Interesting, the documentation doesn't mention this.
From perlop...

A (file)glob evaluates its (embedded) argument only when it is starting
a new list. All values must be read before it will start over. In list
context, this isn't important because you automatically get them all
anyway. However, in scalar context the operator returns the next value
each time it's called, or undef when the list has run out. So if you're
expecting a single value from a glob, it is much better to say

($file) = <blurch*>;

than

$file = <blurch*>;

because the latter will alternate between returning a filename and
returning false.

If you're trying to do variable interpolation, it's definitely better
to use the glob() function, because the older notation can cause people
to become confused with the indirect filehandle notation.

@files = glob("$dir/*.[ch]");
@files = glob($files[$i]);
 
B

Brian McCauley

Eden said:
[ A damn good question ]

I think we (the regulars here) are often seen as being overly critical
of people who ask questions.

So it is worth taking time out once in a while to congratuate someone
on a question well asked.

Good subject line.

Good clear concise explaination.

Good (real, concise) code examples.

The answer could not be trivially found in the FAQ or manuals.
Admittedly all the requisite information is in perlop but it was not so
obvious that Eden deserves any criticism for failing to spot it.
 
U

Uri Guttman

BM> glob() (or <...> used as glob() ) in a scalar context has weird magical
BM> memory attached to where it is called from.

BM> You need to force a list context on glob().

BM> my($dir) = grep { -d $_ && @{[<$_/*.esd>]} } glob($self->inputFolder
BM> .'/*');

BM> my($dir) = grep { -d $_ && (()=<$_/*.esd>) } glob($self->inputFolder
BM> .'/*');

i tend to avoid glob altogether. File::Slurp has a read_dir sub which
will do that and never go into that wacky scalar mode. the use of two
globs is odd as well since they could be combined in the glob() call:

my($dir) = grep -d, glob( $self->inputFolder() . '*.esd' ) ;

or with slurp:

use File::Slurp ;

my( $dir ) = grep -d && /\.esd$/, read_dir( $self->inputFolder() ) ;

doing a glob (any style or context) is the silly mistake here. grep can
do the same thing and is more perlish and uses perl's full regexes vs
glob's dinky patterns. read_dir and grep effectively replace glob except
where you must use glob patterns (and those are easily converted to perl
regexes).

uri
 
B

Brian McCauley

Uri said:
i tend to avoid glob altogether. File::Slurp has a read_dir sub which
will do that and never go into that wacky scalar mode. the use of two
globs is odd as well since they could be combined in the glob() call:

my($dir) = grep -d, glob( $self->inputFolder() . '*.esd' ) ;

The OP wants the file containing the file with the esd suffix.


my($dir) = glob( $self->inputFolder() . '/*.esd' ) ;
$dir =~ s{/[^/]+}{} if $dir;
or with slurp:

use File::Slurp ;

my( $dir ) = grep -d && /\.esd$/, read_dir( $self->inputFolder() ) ;

I can't see an obvious way to do what the OP wants with a single
read_dir.
 
U

Uri Guttman

BM> The OP wants the file containing the file with the esd suffix.

that sounds like a file read itself needs to be done which i haven't
seen. i will need to revisit the OP to see what is wanted.

BM> my($dir) = glob( $self->inputFolder() . '/*.esd' ) ;
BM> $dir =~ s{/[^/]+}{} if $dir;

BM> I can't see an obvious way to do what the OP wants with a single
BM> read_dir.

if i could figure out what the OP wants or if you got it right. as
always the key to a good solution is a good spec. i hate trying to fix
code examples without a properly specified goal.

uri
 
E

Eden Cardim

BM> The OP wants the file containing the file with the esd suffix.
that sounds like a file read itself needs to be done which i haven't
seen.

Well, not really, directories are also files, in Perl's point of view.
from perlfunc:

-d File is a directory.
if i could figure out what the OP wants or if you got it right. as
always the key to a good solution is a good spec. i hate trying to fix
code examples without a properly specified goal.

So, from the OP, what I need is to select a directory (a special type
of file), that contains files ending in '.esd'. "BM" got it right and
his answer was pretty helpful and fixed the bug.
 
E

Eden Cardim

Brian McCauley escreveu:
Eden said:
[ A damn good question ]

I think we (the regulars here) are often seen as being overly critical
of people who ask questions.

So it is worth taking time out once in a while to congratuate someone
on a question well asked.

Good subject line.

Good clear concise explaination.

Good (real, concise) code examples.

The answer could not be trivially found in the FAQ or manuals.
Admittedly all the requisite information is in perlop but it was not so
obvious that Eden deserves any criticism for failing to spot it.

Thanks for the compliment, I think all the issues you mentioned come
spontaneously in a question post when the poster really needs to get an
answer quickly.
 
U

Uri Guttman

BM> The OP wants the file containing the file with the esd suffix.
EC> Well, not really, directories are also files, in Perl's point of
EC> view. from perlfunc:

EC> -d File is a directory.

duh!!

EC> So, from the OP, what I need is to select a directory (a special type
EC> of file), that contains files ending in '.esd'. "BM" got it right and
EC> his answer was pretty helpful and fixed the bug.

it is still done better without globs.

my( $dir ) = grep -d && /\.esd$/, read_dir( $self->inputFolder() ) ;

since read_dir would fail and return an empty list you would just need
to drop the -d test and this should be a boolean test:

my( $is_esd_dir ) = grep /\.esd$/, read_dir( $self->inputFolder() ) ;

uri
 
E

Eden Cardim

Uri Guttman escreveu:
it is still done better without globs.

my( $dir ) = grep -d && /\.esd$/, read_dir( $self->inputFolder() ) ;

since read_dir would fail and return an empty list you would just need
to drop the -d test and this should be a boolean test:

my( $is_esd_dir ) = grep /\.esd$/, read_dir( $self->inputFolder() ) ;

You still didn't get it. Let me set up an imaginary scenario to help
you picture it a little better:

this is my base directory: /usr/local/myapp/input
the base directory contains 2 subdirectories:
/foo - an empty directory
/bar - contains (file1.esd, file2.esd)

so, after I run
my( $is_esd_dir ) = grep /\.esd$/, read_dir( $self->inputFolder() ) ;

$is_esd_dir will always evaluate to false because neither /foo or /bar
end with .esd, Another read_dir/grep would be necessary:

my( $is_esd_dir ) = grep { grep { /.esd$/ } read_dir($_) } read_dir(
$self->inputFolder() ) ;

or, using glob:

my( $is_esd_dir ) = grep { @{[<$_/*.esd>]} } read_dir(
$self->inputFolder() ) ;

I find the version using glob to be a bit more readable and
straightfoward to me.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top