145

I have directory structure like this

data
|___
   |
   abc
    |____incoming
   def
    |____incoming
    |____processed
   123
    |___incoming
   456
    |___incoming
    |___processed

There is an incoming sub-folder in all of the folders inside Data directory. I want to get all files from all the folders and sub-folders except the def/incoming and 456/incoming dirs. I tried out with following command

 find /home/feeds/data -type d \( -name 'def/incoming' -o -name '456/incoming' -o -name arkona \) -prune -o -name '*.*' -print

but it is not working as expected.

Ravi

Ravi
  • 7,939
  • 14
  • 40
  • 43
  • 4
    This is not good advice, but it will get you out of a lot of situations quick and dirty: pipe that to `grep -v something` to exclude whatever it is you don't want – Miquel Nov 19 '12 at 19:18
  • Does this answer your question? [How to exclude a directory in find . command](https://stackoverflow.com/questions/4210042/how-to-exclude-a-directory-in-find-command) – imz -- Ivan Zakharyaschev Feb 04 '20 at 00:29

6 Answers6

251

This works:

find /home/feeds/data -type f -not -path "*def/incoming*" -not -path "*456/incoming*"

Explanation:

  • find /home/feeds/data: start finding recursively from specified path
  • -type f: find files only
  • -not -path "*def/incoming*": don't include anything with def/incoming as part of its path
  • -not -path "*456/incoming*": don't include anything with 456/incoming as part of its path
sampson-chen
  • 45,805
  • 12
  • 84
  • 81
  • getting an error "find: bad option -not find: path-list predicate-list" – Ravi Nov 19 '12 at 19:28
  • @Ravi are you using bash shell? I just tested this on my terminal and it works for me. Try copy and pasting the solution instead if you made modifications to your script. – sampson-chen Nov 19 '12 at 19:30
  • Its working, but, its listing the dirs not files in those dirs. – Ravi Nov 19 '12 at 19:45
  • @Ravi oh, sorry - I confused what you were looking for. Change `type d` to `-type f` and it will find files instead of directories (See updated answer) – sampson-chen Nov 19 '12 at 19:53
  • 4
    `-path` matches the whole string, so if you're doing `find .`, then your `-path` strings need to be `./path/to/directory/*` – Heath Borders Nov 14 '14 at 22:34
  • 4
    FYI `-not -path` definitely will work in this example but `find` is still iterating into the directory structure and using cpu cycles to iterate over all those directories/files. to prevent `find` from iterating over those directories/files (maybe there are millions of files there) then you need to use `-prune` (the `-prune` option is difficult to use however). – Trevor Boyd Smith Feb 19 '19 at 14:22
13

Just for the sake of documentation: You might have to dig deeper as there are many search'n'skip constellations (like I had to). It might turn out that prune is your friend while -not -path won't do what you expect.

So this is a valuable example of 15 find examples that exclude directories:

http://www.theunixschool.com/2012/07/find-command-15-examples-to-exclude.html

To link to the initial question, excluding finally worked for me like this:

find . -regex-type posix-extended -regex ".*def/incoming.*|.*456/incoming.*" -prune -o -print 

Then, if you wish to find one file and still exclude pathes, just add | grep myFile.txt.

It may depend also on your find version. I see:

$ find -version
GNU find version 4.2.27
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION SELINUX
peter_the_oak
  • 3,529
  • 3
  • 23
  • 37
5

-name only matches the filename, not the whole path. You want to use -path instead, for the parts in which you are pruning the directories like def/incoming.

Brian Campbell
  • 322,767
  • 57
  • 360
  • 340
2
find $(INP_PATH} -type f -ls |grep -v "${INP_PATH}/.*/"
Pang
  • 9,564
  • 146
  • 81
  • 122
  • 7
    Some explanations might make this into a much better answer. – Cris Luengo Jan 17 '18 at 23:05
  • Thank you for this code snippet, which might provide some limited short-term help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem, and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you've made – Shawn C. Jan 18 '18 at 04:28
  • 1
    Note: This trick does not work if one uses `find ... -print0` in conjunction with a later `xargs -0` – phs Nov 28 '18 at 12:58
2

By following answer for How to exclude a directory in find . command:

find . \( -name ".git" -o -name "node_modules" \) -prune -o -print
alper
  • 2,919
  • 9
  • 53
  • 102
0

This is what I did to exclude all the .git directories and passed it to -exec for greping something in the

find . -not -path '*/\.*' -type f -exec grep "pattern" [] \;
  • -not -path '*/\.*' will exclude all the hidden directories
  • -type f will only list type file and then you can pass that to -exec or whatever you want todo
phoenixstudio
  • 1,776
  • 1
  • 14
  • 19
kedar
  • 41
  • 2