1

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?

Oliver Salzburg
89.4k65 gold badges270 silver badges312 bronze badges
asked Feb 22, 2012 at 0:41

1 Answer 1

5

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
answered Feb 22, 2012 at 1:32
2
  • 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 ;) Commented Feb 22, 2012 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. Commented Feb 22, 2012 at 18:08

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.