using wildcards with -e

D

DMB

I have the following code:

if (-e $done_dir."BOB.DOC") {
print "found it\n";
} else {
print "nope\n";
}

where $done_dir contains the directory path of the file I'm looking
for.

I'd like to make it so that it doesn't matter what the filename is.
I'm only interested in the suffix. I was thinking along the lines
of...

if (-e $done_dir."*.DOC") {
print "found it\n";
} else {
print "nope\n";
}

but of course this does not work in perl. I'm sure there is an easy
solution to this, but I can't seem to find a example online or in any
of my books of using -e and wildcards.

Thank you for your assistance.
 
P

Peter Makholm

DMB said:
I'd like to make it so that it doesn't matter what the filename is.
I'm only interested in the suffix. I was thinking along the lines
of...

if (-e $done_dir."*.DOC") {
print "found it\n";
} else {
print "nope\n";
}

You might want to look at the glob function which expands these kinds
of wildcards into a list of files. So something like

if (grep { -e $_ } glob("$donedir/*.DOC") ) {
print "Found it";
}

//Makholm
 
D

DMB

You might want to look at the glob function which expands these kinds
of wildcards into a list of files. So something like

if (grep { -e $_ } glob("$donedir/*.DOC") ) {
print "Found it";

}

//Makholm

Great! I'm reading on glob now. I'm not sure I fully understand it
yet, but your example worked perfectly when I tested it.

Thank you.
 
J

John W. Krahn

Peter said:
You might want to look at the glob function which expands these kinds
of wildcards into a list of files. So something like

if (grep { -e $_ } glob("$donedir/*.DOC") ) {
print "Found it";
}

You shouldn't need the grep, this should work:

if ( glob "$donedir/*.DOC" ) {
print "Found it";
}


John
 
M

Michele Dondi

if (-e $done_dir."*.DOC") {
print "found it\n";
} else {
print "nope\n";
}

but of course this does not work in perl. I'm sure there is an easy
solution to this, but I can't seem to find a example online or in any
of my books of using -e and wildcards.

if (grep -e, glob "$done_dir*.DOC") {


Michele
 
M

Michele Dondi

You shouldn't need the grep, this should work:

if ( glob "$donedir/*.DOC" ) {
print "Found it";
}

D'Oh! Just as obvious as I also missed that!


Michele
 
P

Peter Makholm

John W. Krahn said:
You shouldn't need the grep, this should work:

if ( glob "$donedir/*.DOC" ) {
print "Found it";
}

How could I miss that. I didn't even think about what kind of file
test was being used.

//Makholm
 
P

Paul Lalli

You shouldn't need the grep, this should work:

if ( glob "$donedir/*.DOC" ) {
print "Found it";
}

Danger, danger Will Robinson!! That bit of code will work only if
both of the following are true:
1) The string actually does contain shell meta characters.
2) The block is not being used in a loop.

If you later change your "pattern" to actualy be a single file, your
code will break. This is especially a problem if you're reading the
pattern from the user. Observe:

~/temp $ ls
~/temp $ perl -le'print for glob("foo.*")'
~/temp $ perl -le'print for glob("foo.bar")'
foo.bar
~/temp $

If the code is being called in a loop of some kind, and there are, say
N files that match the pattern, your if statement will fail every (N
+1)th time. Observe:

~/temp $ touch foo.1 foo.2 foo.3
~/temp $ perl -le'
for (1..10) {
if (glob("foo.*")) {
print "yes"
} else {
print "no"
}
}
'
yes
yes
yes
no
yes
yes
yes
no
yes
yes


All things considered, it's better to stick with the grep, and thereby
call glob() in a scalar context, explicitly testing the existance of
each return value.

Paul Lalli
 
P

Paul Lalli

All things considered, it's better to stick with the grep, and
thereby call glob() in a scalar context, explicitly testing the
existance of each return value.

s/scalar/list/;

Paul Lalli
 
M

Michele Dondi

If you later change your "pattern" to actualy be a single file, your
code will break. This is especially a problem if you're reading the
pattern from the user. Observe:

Oh, yeah, and there' brace expansion too. Perhaps it was not that bad
to leave the -e in after all...


Michele
 
C

Clenna Lumina

Paul said:
Danger, danger Will Robinson!! That bit of code will work only if
both of the following are true:
1) The string actually does contain shell meta characters.
2) The block is not being used in a loop.

If you later change your "pattern" to actualy be a single file, your
code will break. This is especially a problem if you're reading the
pattern from the user. Observe:

~/temp $ ls
~/temp $ perl -le'print for glob("foo.*")'
~/temp $ perl -le'print for glob("foo.bar")'
foo.bar
~/temp $

If the code is being called in a loop of some kind, and there are, say
N files that match the pattern, your if statement will fail every (N
+1)th time. Observe:

~/temp $ touch foo.1 foo.2 foo.3
~/temp $ perl -le'
for (1..10) {
if (glob("foo.*")) {
print "yes"
} else {
print "no"
}
}
'
yes
yes
yes
no
yes
yes
yes
no
yes
yes

I noticed that if you change:

if (glob("foo.*")) {

to [1]:

my @files = glob("foo.*");
if (@files) {

then you get:

$ ./test.pl
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes

Changing the contents of the loop to [2]:

my @files = glob("foo.*");
print "[". join("]\n[", @files). "]\n\n";

prints the following 10 times:

[foo.1]
[foo.2]
[foo.3]
All things considered, it's better to stick with the grep, and thereby
call glob() in a scalar context, explicitly testing the existance of
each return value.

Paul Lalli

Grep works fine. But I want to know why Glob returns the way it does in
your original code?

In fact, if you change your original 'if' statement to:

if (()=glob("foo.*")) {

then 'yes' is printed every time as expected. Of course, it's being
forced into list context. It seems glob in scalar context is the
problem.


According to my Perl Pocket Reference (4th Ed.), pg 54:

glob expr ?
Returns a list of filenames that match the C-shell
pattern(s) in expr.


Perldoc says this:

$ perldoc -f glob
glob EXPR
glob Returns the value of EXPR with filename expansions
such as the standard Unix shell /bin/csh would do.
This is the internal function implementing the
"<*.c>" operator, but you can use it directly.


So if used in scalar context, shouldn't it be returning 3 (the list
count) in the example we're using?

It seems it shouldn't matter if it's being used in a loop or not, it
should be returning the same each time since what it's fetching is
unchanged?

Does this mean glob is broken in scalar context?



[1]
#!/usr/bin/perl

use strict;

for (1..10) {
my @d = glob("foo.*");
if (@d) {
#if (glob("foo.*")) {
print "yes"
}
else {
print "no"
}

print "\n";
}
__END__


[2]

#!/usr/bin/perl

use strict;

for (1..10) {
my @files = glob("foo.*");
print "[". join("]\n[", @files). "]\n\n";
}
__END__
 
P

Paul Lalli

Grep works fine. But I want to know why Glob returns the way it
does in your original code?

Because glob() does something different depending on if its called in
scalar context or list context.
In fact, if you change your original 'if' statement to:

if (()=glob("foo.*")) {

then 'yes' is printed every time as expected. Of course, it's being
forced into list context. It seems glob in scalar context is the
problem.
Yes.

According to my Perl Pocket Reference (4th Ed.), pg 54:

glob expr ?
Returns a list of filenames that match the C-shell
pattern(s) in expr.

Your pocket reference is wrong. It only returns a list in list
context.
Perldoc says this:

$ perldoc -f glob
glob EXPR
glob Returns the value of EXPR with filename expansions
such as the standard Unix shell /bin/csh would do.
This is the internal function implementing the
"<*.c>" operator, but you can use it directly.

You either have an old and/or broken version of Perldoc, or you oddly
omitted a section. In my perldoc, there is another sentence between
those two:
In scalar
context, glob iterates through such filename
expansions, returning undef when the list is
exhausted.
So if used in scalar context, shouldn't it be returning 3 (the list
count) in the example we're using?

I don't know what makes you think that. Even if your version of the
doc was complete, it still doesn't say that. You may be falling into
the trap of believing that all list-returning functions return the
size of that list in scalar context. That's not true. Arrays
evaluated in scalar context return their size. That's it. You cannot
generalize "array" to "any expression returning a list." Any function
returning a list of values in list context is free to do anything else
in scalar context.
Does this mean glob is broken in scalar context?

No. glob() behaves exactly as it's documented to behave in scalar
context. If your version of perldoc really is missing that critical
section, I suggest you check out the most recent version:
http://perldoc.perl.org/functions/glob.html

Paul Lalli
 
C

Clenna Lumina

Paul said:
Because glob() does something different depending on if its called in
scalar context or list context.

Would it not of been more logical to have it return the count of the
files it found, though?
Your pocket reference is wrong. It only returns a list in list
context.

That would seem to be the case.
You either have an old and/or broken version of Perldoc, or you oddly
omitted a section. In my perldoc, there is another sentence between
those two:

Hmm, I'm using Perl 5.6.1 on RH Linux and it does seem to lack that
section:

perldoc -f glob
glob EXPR
glob Returns the value of EXPR with filename expansions
such as the standard Unix shell /bin/csh would do.
This is the internal function implementing the
"<*.c>" operator, but you can use it directly. If
EXPR is omitted, "$_" is used. The "<*.c>" opera-
tor is discussed in more detail in the I/O Opera-
tors entry in the perlop manpage.

Beginning with v5.6.0, this operator is imple-
mented using the standard "File::Glob" extension.
See the File::Glob manpage for details.
(END)
In scalar
context, glob iterates through such filename
expansions, returning undef when the list is
exhausted.

Well that certainly explains it. FWIW, my pocket book (ISBN
0-596-00374-9) claims it covers Perl 5.8, so it's a little odd that they
left this rather important note out. Same goes for 5.6.1's Perldoc.
I don't know what makes you think that. Even if your version of the
doc was complete, it still doesn't say that. You may be falling into
the trap of believing that all list-returning functions return the
size of that list in scalar context. That's not true. Arrays
evaluated in scalar context return their size. That's it. You cannot
generalize "array" to "any expression returning a list." Any function
returning a list of values in list context is free to do anything else
in scalar context.

Hmm, thanks for pointing that out. Yes it is easy to get into that way
of thinking, when many functions seem to return the count (ie, map,
grep) when used in scalar context.
No. glob() behaves exactly as it's documented to behave in scalar
context.

Question retracted.
If your version of perldoc really is missing that critical
section, I suggest you check out the most recent version:
http://perldoc.perl.org/functions/glob.html

Thank you, I have saved this.
 
P

Paul Lalli

Would it not of been more logical to have it return the count
of the files it found, though?

Not really. Think of glob() as a means of doing readdir() via shell
expansion rather than opening the directory in Perl. That way, you
can do:
while (my $file = glob("*.pl")) {
#...
}
rather than:
open my $dh, "." or die $!;
while (my $file = readdir($dh)) {
next unless $file =~ /\.pl$/;
#...
}

If you want the count of the files, either keep track as you're
reading them in, or read them into an array first and then get the
count of that:
my @files = glob("*.pl");
my $count = @files;
(or, as you found, bastardize the empty-list-assignment feature:
my $count = () = glob("*.pl");
)

You'll note the context-based return value of glob() also matches the
context-based return value of readdir(). All files in list context,
"next" file in scalar context.
Hmm, I'm using Perl 5.6.1 on RH Linux and it does seem to lack that
section:

I'd call that a documentation bug in 5.6.1. I verified the same thing
with a 5.6.1 version on solaris. The function works the same as it
does on 5.8, but the docs lack that rather important note.
Hmm, thanks for pointing that out. Yes it is easy to get into
that way of thinking, when many functions seem to return the
count (ie, map, grep) when used in scalar context.

Oh, I agree. That's why I called it a trap. It gets easier to
remember once you start writing your own subroutines that do something
different depending on context, using the wantarray() function.
Thank you, I have saved this.

You're welcome. Note that I generally recommend you use the version
of the documentation that matches your version of Perl, but in this
case, it's unfortunate that the docs themselves contain a bug..

Paul Lalli
 
C

Clenna Lumina

Paul said:
Would it not of been more logical to have it return the count
of the files it found, though?
[...]
You'll note the context-based return value of glob() also matches the
context-based return value of readdir(). All files in list context,
"next" file in scalar context.

Thought I still have to wonder if it wouldn't of been better for it to
just behave like a normal list? I mean,

for(@arr) { ... }

iterates over the list.

while(@arr) { ... }

OTOH, gives you an infinite loop.

Now that I think about it, that behavior (get next file) is a more
useful, and would result in less memory usage. I guess the only
potential gripe I see is that it behaves in a way you wouldn't expect
the first time you used it.
I'd call that a documentation bug in 5.6.1. I verified the same thing
with a 5.6.1 version on solaris. The function works the same as it
does on 5.8, but the docs lack that rather important note.

Good to know. Thanks.
Oh, I agree. That's why I called it a trap. It gets easier to
remember once you start writing your own subroutines that do something
different depending on context, using the wantarray() function.

Yes I've seen many instances where it returns in a way you don't expect.
Although most of the built in functions (sort, grep, map, ...) that
return lists behave as you expect in scalar context too. 'grep' is
commonly used as an 'if' conditional, for example.
You're welcome. Note that I generally recommend you use the version
of the documentation that matches your version of Perl, but in this
case, it's unfortunate that the docs themselves contain a bug..

I know the people who maintain them do a good job and it's impossible to
keep all of it up to date. I think it can be considered a lesson that
there can always be more to something then just what's written.
 
M

Michele Dondi

Now that I think about it, that behavior (get next file) is a more
useful, and would result in less memory usage. I guess the only

I'm not really sure: I may be wrong but ISTR that glob() reads all the
entries behind the curtains anyway. Or there was some gotcha like
that. If you can call it gotcha...
Yes I've seen many instances where it returns in a way you don't expect.
Although most of the built in functions (sort, grep, map, ...) that
return lists behave as you expect in scalar context too. 'grep' is
commonly used as an 'if' conditional, for example.

ITYM within and if condition.


Michele
 
T

Tad McClellan

Clenna Lumina said:
Although most of the built in functions (sort, grep, map, ...) that
return lists behave as you expect in scalar context too.


You expected that sort() in a scalar context behaves
in an undefined manner?
 
C

Clenna Lumina

Tad said:
You expected that sort() in a scalar context behaves
in an undefined manner?

Hmmm, I stand corrected. I ran some quick command-line tests, showing
that 'map' and 'grep' return the item count but sort does not. It just
seems to return undef:

$ perl -le 'my @list = qw/1 2 4 8 16 32/; print(defined(scalar sort
@list) ? "Y" : "N");'
N

Why is this?

$ perldoc -f sort
sort SUBNAME LIST
sort BLOCK LIST
sort LIST
Sorts the LIST and returns the sorted list value.
[...]

It seems that it is supposed to be returning a list (assuming "list
value", means that it's returning a list, which is the case in list
context.) Having read through the whole article I can't seem to find a
reason why it would returning undef. What use cold this possible have?
Wouldn't it have been more logical to return the same was as 'map' and
'grep' in scalar context?
 
T

Tad McClellan

Clenna Lumina said:
Hmmm, I stand corrected. I ran some quick command-line tests, showing
that 'map' and 'grep' return the item count but sort does not. It just
seems to return undef:

$ perl -le 'my @list = qw/1 2 4 8 16 32/; print(defined(scalar sort
@list) ? "Y" : "N");'
N

Why is this?


perldoc -f sort

sort SUBNAME LIST
sort BLOCK LIST
sort LIST
In list context, this sorts the LIST and returns the sorted list
value. In scalar context, the behaviour of "sort()" is undeâ€
fined.
 
C

Clenna Lumina

Tad said:
perldoc -f sort

sort SUBNAME LIST
sort BLOCK LIST
sort LIST
In list context, this sorts the LIST and returns the
sorted list value. In scalar context, the behaviour of
"sort()" is undeâ? fined.

I understand that it is undefined behavior, but what I'm trying to
determine is what useful purpose could that possibly serve? Why doesn't
it just return the count?

(Note to self, update perldoc.)
 

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

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top