I am running the following to find all directories without a number in them (not including the original path):

find /path/2/directory -type d -name '[!0-9]*'

The problem is that it finds directories that are subdirectories of directories that have numbers.



or even


Is there any way to prevent find from returning such directories?

I cannot solve this problem by limiting the depth, the depth can vary.



4 Answers 4


Use -prune to ignore those directories:

find /path/to/directory -name '*[0-9]*' -prune -o -type d -print

though if you're on a gnu setup you may want to use the C locale when running the above, see Stéphane's comment below.

  • This one worked without any tweaking. Thanks for the help.
    – Mocking
    Mar 3, 2016 at 23:03
  • Note that on GNU systems at least, that will still include directories whose name contains digits and an invalid character. You could fix the locale to C to avoid that. Mar 5, 2016 at 8:51
  • Note that the first -type d is not necessary here. Mar 5, 2016 at 8:51
  • @StéphaneChazelas - yup, thanks for the heads up ! I assume that gnu specific behaviour is a known bug ? @Mocking - it doesn't need tweaking because it uses the right pattern with -name as opposed to Anthon's solution, see my comments under his answer. Mar 5, 2016 at 14:11
  • 1
    Not really a bug, * is 0 or more characters, so doesn't match non-characters. Behaviour differs across implementations. Same as for regexps, . matches a character, so .* doesn't match across non-characters in most implementations. When it comes to shells * and ? in practice do match bytes that don't form part of valid characters (even though at least for ? that's against POSIX (and something that needs to be addressed in the spec). Mar 6, 2016 at 18:15

If you don't want find to descent beyond a certain match you should use -prune and not e.g. -path or filtering the output of find with grep -v

To test things out make an environment with some extra files and subdirs, so you can check your find not to display unwanted material:

mkdir -p tmp/2/abc/def
touch tmp/2/abc/def/file1
mkdir -p tmp/2/abc/9876/xyz
touch tmp/2/abc/9876/xyz/file2
tree tmp/


└── 2
    └── abc
        ├── 9876
        │   └── xyz
        │       └── file2
        └── def
            └── file1

If you do find tmp/2/abc \! -path "*[0-9]*" as suggested by @terdon, the output will be empty, because -path doesn't just take into account the directories starting below abc but the whole path, which includes 2. So that is not what you want.

If you do find tmp/2/abc -type d | grep -vE '/[0-9-]+(/|$)', as suggested by @cas, you'll find that it doesn't print anything either, again because it matcheds not just the files down from where you're searching but also the directory named 2. Apart from that this would require find to first walk the whole tree under 9876 and if there are a few hundred thousand items there the walking (and filtering) will take a noticable amount of time.

If you do:

find tmp/2/abc -type d -name '[!0-9]*' -print 

you will find that the output includes the path tmp/2/abc/9876/xyz. To get rid of that cut off what you don't want with -prune:

find tmp/2/abc -type d -name '[!0-9]*' -print -o -name '[0-9]*' -prune

which gives:


you can slightly improve the on the efficiency of that by swapping the pruning and printing which is what @don_cristti did in his enhancement of this answer.

  • I am aware of maxdepth but the depth can vary. Thanks though.
    – Mocking
    Mar 3, 2016 at 22:40
  • @Mocking I noticed, you have to prune matching directories that have numbers, I updated the answer
    – Anthon
    Mar 3, 2016 at 22:43
  • I'm gonna upvote this since you posted prune first but it didn't work for some cases even when I tweaked it. @don_crissti had a copy and paste working one. Thanks for the help though. Edit: Nevermind I don't have enough rep.
    – Mocking
    Mar 3, 2016 at 23:03
  • fwiw, your post and terdon's weren't working OK when I posted mine and they're still not working fine - at least on my setup; terdon's has the flaws you mentioned and it prints also regular file names and yours doesn't work as expected - I had to replace -name '[!0-9]*' with ! -name '*[0-9]*' (and use the same '*[0-9]*' for the second -name) to make it work. Mar 5, 2016 at 11:05
  • without details of your setup it is easy to claim they are not working fine and that a minor tweak is necessary, that is why I included my test environment in my answer and pointed out the issues with the others.
    – Anthon
    Mar 5, 2016 at 11:12

I think you're looking for -path:

   -path pattern
          File  name matches shell pattern pattern.  The metacharacters do
          not treat `/' or `.' specially; so, for example,
                    find . -path "./sr*sc"
          will print an entry for a directory called `./src/misc' (if  one

It searches the entire path of each file/directory for the given pattern. So, if you have a directory structure like this:

$ tree
├── 111
│   └── foo
│       └── bar
├── bar
│   └── foo
│       └── baz
└── foo
    └── 111
        └── bar

9 directories, 0 files

You can use find like this:

$ find /path/to/directory/ \! -path "*[0-9]*" 

Or, with GNU find:

find /path/to/directory/ -not -path "*[0-9]*" 

Since this will have to descend into each directory to check its name, it will be significantly slower on large directory trees than @Anthon's solution with prune. If you don't have thousands of directories, though, it should be fine.

  • This would have been almost perfect, the problem I think is that my original /path/to/directory has a number in it. This is my fault for not clarifying the problem, I edited my question.
    – Mocking
    Mar 3, 2016 at 23:01

It's easy to use grep (or awk or sed or perl etc) to remove such directories from find's output:

find /path/to/directory -type d | grep -vE '/[0-9-]+(/|$)'

Note: I've included - in the character class because dated directories are sometimes YYYY-MM-DD rather than just YYYYMMDD

  • Of course it might be horrible expensive (in time) to first descend into subdirectories that you know you can ignore upfront
    – Anthon
    Mar 3, 2016 at 22:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .