Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I'm using bash for Mac OS X 10.6.8.

Using the find command, I would like to search for files that match *.XML. However, I would like to match only those files in the 16xxxx sub-directory and not 16yyyy from some base directory.

basedir/16xxxx/EX1.XML
basedir/16xxxx/EX2.XML
basedir/16yyyy/EX3.XML
basedir/16yyyy/EX4.XML

The results I'm looking for would be EX1.XML and EX2.XML (full path name excluded for clarity).

This is in the context of a BASH script which would make it convenient if I could enter 16xxxx/*.XML as the expression to pass to -name in the find command:

find basedir -name '16xxxx/*.XML'

However, this does not return any matches because the shell doesn't match the / character. Is there some argument to pass to find or a way to escape the 16xxxx/\*.XML expression that will return the results I need?

share|improve this question
add comment

1 Answer

up vote 3 down vote accepted

The -name option is never going to work past the first /. As always, man pages are your friends:

 -path pattern
         True if the pathname being examined matches pattern.  Special shell pattern matching characters
         (``['', ``]'', ``*'', and ``?'') may be used as part of pattern.  These characters may be
         matched explicitly by escaping them with a backslash (``\'').  Slashes (``/'') are treated as
         normal characters and do not have to be matched explicitly.

I usually prefer compatibility with GNU find, and therefore use the -wholename option. Nothe that these also exist in case-insensitive mode: -iwholename and -ipath.

So in your case, you'd do (remember that wholename matches the whole path, so you have to add the wildcard * at the beginning):

karolos$ find basedir -type f
basedir/16xxxx/EX1.XML
basedir/16xxxx/EX2.XML
basedir/16yyyy/EX3.XML
basedir/16yyyy/EX4.XML
karolos$ find basedir -wholename "*16xxxx/*.XML"
basedir/16xxxx/EX1.XML
basedir/16xxxx/EX2.XML

Another way to achieve what you want is to use find in combination with grep (note that I had to alter the regular expression, adding a . (for any caracter) before the wildcard *):

karolos$ find basedir | grep '16xxxx/.*.XML'
basedir/16xxxx/EX1.XML
basedir/16xxxx/EX2.XML

Finally, depending on your needs, there is even the possibility that you don't even need to use find (if you don't need the extra flexibility). You can then use bash filename expansion as follows:

karolos$ echo basename/*16x*/*XML
basename/16xxxx/EX1.XML basename/16xxxx/EX2.XML
share|improve this answer
    
Thanks for this. I tried -wholename during my efforts yesterday but didn't try the wildcard. I tried my best to avoid the RTFM comments (I read the manual), but I'll need to try harder ;) –  stever Feb 22 '12 at 16:17
    
@stever: You're welcome. Manual pages for GNU tools are usually well documented, but the *nix jargon is not always straightforward at first. The leading wildcard catch is indeed something easy to miss. –  Karolos Feb 22 '12 at 18:08
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.