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/
gives:
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:
tmp/2/abc
tmp/2/abc/def
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.