LinuxQuestions.org
Visit the LQ Articles and Editorials section
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
 
Search this Thread
Old 03-01-2014, 06:02 PM   #1
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: xubuntu
Posts: 202

Rep: Reputation: 21
bash pattern matching


Code:
for file in ?(s*|p*); do echo $file; done
gives me a list of filenames beginning with 's' or 'p'

Code:
for file in *; do echo $file; done
gives me a list of all filenames not beginning with '.'
Code:
for file in .[^.]*; do echo $file; done
gives me a list of filenames beginning with '.' (except for "." and "..")


so why does
Code:
for file in ?(.[^.]*|*); do echo $file; done
list only files not beginning with '.'?
 
Old 03-01-2014, 06:49 PM   #2
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,658

Rep: Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916
It's simply that if dotglob is unset, a glob pattern must begin with a dot in order to match a filename beginning with a dot. Starting with pattern that matches a dot isn't good enough.

Code:
.*   # matches filenames starting with dot
[a]* # matches filenames starting with a
[.]* # only if dotglob is set, matches filenames starting with dot
From Filename Expansion:
Quote:
When a pattern is used for filename expansion, the character . at the start of a filename or immediately following a slash must be matched explicitly, unless the shell option dotglob is set.
 
Old 03-01-2014, 09:13 PM   #3
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: xubuntu
Posts: 202

Original Poster
Rep: Reputation: 21
Thanks. I've been studying that section of the manual, but the behavior I'm seeing doesn't seem to follow the rule.

My third example .[^.]* has a leading . which explicitly matches the hidden filenames, and indeed the command does list the hidden files.

My fourth example ?(.[^.]*|*) is an instance of a pattern list described in Pattern Matching, and the first entry in my pattern list is the same expression .[^.]* that I used in the third example, with the same leading . to explictly match the hidden filenames. So why doesn't that work when it's in a pattern list? I don't see anything in the manual to explain this.
 
Old 03-02-2014, 09:43 AM   #4
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,563
Blog Entries: 29

Rep: Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179
Presumably the ? -- which the linked page says "Matches any single character" -- matches any single character except .
 
Old 03-02-2014, 09:57 AM   #5
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,658

Rep: Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916
Quote:
Originally Posted by r.stiltskin View Post
and the first entry in my pattern list is the same expression .[^.]* that I used in the third example, with the same leading . to explictly match the hidden filenames.
Except that it's no longer leading! It's part of the ?(...) pattern.

Code:
a*    # files starting with a
@(a)* # files starting with a
@(a*) # files starting with a
.*    # files starting with dot
@(.)* # only if dotglob is set, files starting with dot
@(.*) # only if dotglob is set, files starting with dot
 
Old 03-02-2014, 10:38 AM   #6
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: xubuntu
Posts: 202

Original Poster
Rep: Reputation: 21
Quote:
Originally Posted by catkin View Post
Presumably the ? -- which the linked page says "Matches any single character" -- matches any single character except .
This does not apply. Please read the bottom of the page Pattern-Matching. The leading ? in ?(pattern-list) doesn't match anything. It is simply a part of the ?(...) structure which matches zero or one of the patterns listed between the parentheses.
 
1 members found this post helpful.
Old 03-02-2014, 11:02 AM   #7
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: xubuntu
Posts: 202

Original Poster
Rep: Reputation: 21
Quote:
Originally Posted by ntubski View Post
Except that it's no longer leading! It's part of the ?(...) pattern.
I don't disagree with your examples, which more or less restate and reinforce my original examples. But I still don't see anything in the manual that explains this behavior. Your statement that "...it's no longer leading! It's part of the ?(...) pattern" is true, but how does that follow from the actual documentation, which says only that:
Quote:
Bash Manual Sec. 3.5.8 Filename Expansion:

...the character . at the start of a filename or immediately following a slash must be matched explicitly, unless the shell option dotglob is set.
and
Quote:
Bash Manual Sec. 3.5.8 Filename Expansion:

?(pattern-list)

Matches zero or one occurrence of the given patterns.
It seems to me that ?(.*) gives a pattern (or to be precise, a subpattern) that explicitly matches the '.' character at the start of a filename. Oh well, I guess I will have to accept it as a documentation bug (or at least an ambiguity).
 
Old 03-02-2014, 12:21 PM   #8
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,658

Rep: Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916
Quote:
Originally Posted by r.stiltskin View Post
?(.*) gives a pattern (or to be precise, a subpattern)
Right, and the leading dot condition doesn't apply to subpatterns, only to whole ones. Or, to put it another way, "matched explicitly" means a leading dot, not a pattern that matches a leading dot.

Last edited by ntubski; 03-02-2014 at 12:21 PM. Reason: clarity
 
Old 03-02-2014, 05:01 PM   #9
KenJackson
Member
 
Registered: Jul 2006
Location: Maryland, USA
Distribution: Fedora, PCLinuxOS
Posts: 580

Rep: Reputation: 65
I find globs to be less powerful and more frustrating than regular expressions. But alas, we're stuck with globs.

Does this do what you want?
Code:
for file in .* *; do echo $file; done
 
Old 03-02-2014, 05:38 PM   #10
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: xubuntu
Posts: 202

Original Poster
Rep: Reputation: 21
Quote:
Originally Posted by ntubski View Post
Right, and the leading dot condition doesn't apply to subpatterns, only to whole ones.
I can't find anything in the Bash Manual to support that claim. A careful review of the relevant section reveals that ?(pattern-list) is not a pattern, it is an "extended pattern matching operator". The manual then provides this definition:
Quote:
a pattern-list is a list of one or more patterns separated by a |
and explains that
Quote:
?(pattern-list)

Matches zero or one occurrence of the given patterns.
and so if one of the given patterns (or the only one) happens to be .*, it begins with a dot. An explicit, unambiguous, fully-formulated dot. Not a special pattern character nor a range expression nor a character class nor anything else that can be construed or interpreted as a dot. A dot. Therefore it should satisfy the requirement that "the character . at the start of a filename or immediately following a slash must be matched explicitly."

We will have to agree to disagree.
 
Old 03-02-2014, 05:50 PM   #11
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: xubuntu
Posts: 202

Original Poster
Rep: Reputation: 21
Quote:
Originally Posted by KenJackson View Post
I find globs to be less powerful and more frustrating than regular expressions. But alas, we're stuck with globs.

Does this do what you want?
Code:
for file in .* *; do echo $file; done
Hi,

Almost. thanks.

This does:
Code:
for file in .[^.]* *; do echo $file; done
It (almost) seems to make the entire discussion about pattern lists irrelevant, doesn't it?

But the "for file in ..." construct was just an example for purposes of discussion. There must be other contexts in which you can't just place a "barenaked" list of expressions in your command but instead must use the "extended pattern matching operators" described in Pattern-Matching.
 
Old 03-02-2014, 09:57 PM   #12
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,658

Rep: Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916
This is all angels-on-the-head-of-a-pin stuff anyway, right? If you want sane behaviour, set dotglob and nullglob.

Perhaps the manual could be improved, but it does say (highlight added):
Quote:
Bash scans each word for the characters *, ?, and [. If one of these characters appears, then the word is regarded as a pattern,
The whole word is one pattern, so you can't break apart sub-patterns and treat them separately. The whole pattern matches, or none of it does. I think the extended patterns section referring to the pattern-list elements as patterns is simply unfortunate wording.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Bash Version 3.1 to 3.2 and Later --- Inconsistent Pattern Matching mrm5102 Programming 10 07-17-2012 02:00 PM
Bash: Pattern matchin - how to do matching on a variable? SQADude Programming 23 12-09-2009 01:47 AM
Pattern matching in BASH. ccin1492 Programming 8 12-19-2008 11:00 AM
bash script pattern matching thedude2010 Programming 9 06-02-2006 02:39 AM
Pattern Matching Help in Bash script cmfarley19 Programming 1 04-07-2004 09:22 AM


All times are GMT -5. The time now is 08:13 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration