How do I exclude a directory when using `find`?

Questions : How do I exclude a directory when using `find`?

How do I exclude a specific directory when searching for *.js files using find?

find . -name '*.js' 

Total Answers: 46 Answers 46

Popular Answers:

  1. Use the -prune primary. For example, if you want to exclude ./misc:

    find . -path ./misc -prune -o -name '*.txt' -print 

    To exclude multiple directories, OR them between parentheses.

    find . -type d ( -path ./dir1 -o -path ./dir2 -o -path ./dir3 ) -prune -o -name '*.txt' -print 

    And, to exclude directories with a specific name at any level, use the -name primary instead of -path.

    find . -type d -name node_modules -prune -o -name '*.json' -print 
  2. Use the -prune primary. For example, if you want to exclude ./misc:

    find . -path ./misc -prune -o -name '*.txt' -print 

    To exclude multiple directories, OR them between parentheses.

    find . -type d ( -path ./dir1 -o -path ./dir2 -o -path ./dir3 ) -prune -o -name '*.txt' -print 

    And, to exclude directories with a specific name at any level, use the -name primary instead of -path.

    find . -type d -name node_modules -prune -o -name '*.json' -print 
  3. I find the following easier to reason about than other proposed solutions:

    find build -not ( -path build/external -prune ) -name *.js # you can also exclude multiple paths find build -not ( -path build/external -prune ) -not ( -path build/blog -prune ) -name *.js 

    Important Note: the paths you type after -path must exactly match what find would print without the exclusion. If this sentence confuses you just make sure to use full paths through out the whole command like this: find /full/path/ -not ( -path /full/path/exclude/this -prune ) .... See note [1] if you’d like a better understanding.

    Inside ( and ) is an expression that will match exactly build/external (see important note above), and will, on success, avoid traversing anything below. This is then grouped as a single expression with the escaped parenthesis, and prefixed with -not which will make find skip anything that was matched by that expression.

    One might ask if adding -not will not make all other files hidden by -prune reappear, and the answer is no. The way -prune works is that anything that, once it is reached, the files below that directory are permanently ignored.

    This comes from an actual use case, where I needed to call yui-compressor on some files generated by wintersmith, but leave out other files that need to be sent as-is.

    Note [1]: If you want to exclude /tmp/foo/bar and you run find like this “find /tmp (...” then you must specify -path /tmp/foo/bar. If on the other hand you run find like this cd /tmp; find . (... then you must specify -path ./foo/bar.

  4. There is clearly some confusion here as to what the preferred syntax for skipping a directory should be.

    GNU Opinion

    To ignore a directory and the files under it, use -prune 

    From the GNU find man page


    -prune stops find from descending into a directory. Just specifying -not -path will still descend into the skipped directory, but -not -path will be false whenever find tests each file.

    Issues with -prune

    -prune does what it’s intended to, but are still some things you have to take care of when using it.

    1. find prints the pruned directory.

      • TRUE That’s intended behavior, it just doesn’t descend into it. To avoid printing the directory altogether, use a syntax that logically omits it.
    2. -prune only works with -print and no other actions.

      • NOT TRUE. -prune works with any action except -delete. Why doesn’t it work with delete? For -delete to work, find needs to traverse the directory in DFS order, since -deletewill first delete the leaves, then the parents of the leaves, etc… But for specifying -prune to make sense, find needs to hit a directory and stop descending it, which clearly makes no sense with -depth or -delete on.


    I set up a simple test of the three top upvoted answers on this question (replaced -print with -exec bash -c 'echo $0' {} ; to show another action example). Results are below

    ---------------------------------------------- # of files/dirs in level one directories .performance_test/prune_me 702702 .performance_test/other 2 ---------------------------------------------- > find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} ; .performance_test .performance_test/other .performance_test/other/foo [# of files] 3 [Runtime(ns)] 23513814 > find ".performance_test" -not ( -path ".performance_test/prune_me" -prune ) -exec bash -c 'echo "$0"' {} ; .performance_test .performance_test/other .performance_test/other/foo [# of files] 3 [Runtime(ns)] 10670141 > find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} ; .performance_test .performance_test/other .performance_test/other/foo [# of files] 3 [Runtime(ns)] 864843145 


    Both f10bit’s syntax and Daniel C. Sobral’s syntax took 10-25ms to run on average. GetFree’s syntax, which doesn’t use -prune, took 865ms. So, yes this is a rather extreme example, but if you care about run time and are doing anything remotely intensive you should use -prune.

    Note Daniel C. Sobral’s syntax performed the better of the two -prune syntaxes; but, I strongly suspect this is the result of some caching as switching the order in which the two ran resulted in the opposite result, while the non-prune version was always slowest.

    Test Script

    #!/bin/bash dir='.performance_test' setup() { mkdir "$dir" || exit 1 mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z"  "$dir/other" find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} ; find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} ; touch "$dir/other/foo" } cleanup() { rm -rf "$dir" } stats() { for file in "$dir"/*; do if [[ -d "$file" ]]; then count=$(find "$file" | wc -l) printf "%-30s %-10sn" "$file" "$count" fi done } name1() { find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"' {} ; } name2() { find "$dir" -not ( -path "$dir/prune_me" -prune ) -exec bash -c 'echo "$0"' {} ; } name3() { find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} ; } printf "Setting up test files...nn" setup echo "----------------------------------------------" echo "# of files/dirs in level one directories" stats | sort -k 2 -n -r echo "----------------------------------------------" printf "nRunning performance test...nn" echo > find """$dir"""" -path """"$dir/prune_me"""" -prune -o -exec bash -c 'echo ""$0""' {} \; name1 s=$(date +%s%N) name1_num=$(name1 | wc -l) e=$(date +%s%N) name1_perf=$((e-s)) printf "" [# of files] $name1_num [Runtime(ns)] $name1_perfnn"" echo > find """"$dir"""" -not \( -path """"$dir/prune_me"""" -prune \) -exec bash -c 'echo ""$0""' {} \; name2 s=$(date +%s%N) name2_num=$(name2 | wc -l) e=$(date +%s%N) name2_perf=$((e-s)) printf "" [# of files] $name2_num [Runtime(ns)] $name2_perfnn"" echo > find """"$dir"""" -not -path """"$dir/prune_me*"""" -exec bash -c 'echo ""$0""' {} \; name3 s=$(date +%s%N) name3_num=$(name3 | wc -l) e=$(date +%s%N) name3_perf=$((e-s)) printf "" [# of files] $name3_num [Runtime(ns)] $name3_perfnn"" echo ""Cleaning up test files..."" cleanup 

  5. This is the only one that worked for me.

    find / -name MyFile ! -path '*/Directory/*' 

    Searching for “MyFile” excluding “Directory”. Give emphasis to the stars * .

  6. One option would be to exclude all results that contain the directory name with grep. For example:

    find . -name '*.js' | grep -v excludeddir 
  7. Tested in Linux Ubuntu 18.04 and 20.04.

    find is incredibly important and powerful, but it is so nuanced and confusing!

    How do I exclude a specific directory when searching for *.js files using find?

    Quick summary and answer:

    Follow these patterns. See also my comment here. These are the best and most-effective patterns I have found, period. The escaped parenthesis (( and )) and the -prune option are very important. Read below to find out why.

    Best patterns to use:

    Remove the -name '*.js' part of each command below, of course, if you are looking for a generic answer and not trying to solve the OP’s original question, which involved also finding only files with extension .js in their name.

    # exclude one path, and its contents, saving time by *not* recursing down the # excluded path at all find . -name '*.js' -not ( -path "./dir_to_exclude" -prune ) # exclude multiple paths and their contents, saving time by *not* recursing down # the excluded paths at all find . -name '*.js'  -not ( -path "./dir_to_exclude1" -prune )  -not ( -path "./dir_to_exclude2" -prune )  -not ( -path "./dir_to_exclude3" -prune ) # If you change your "starting point" path from `.` to something else, be sure # to update the beginning of your `-path` with that as well, like this: find "some_dir" -name '*.js' -not ( -path "some_dir/dir_to_exclude" -prune ) find "some_dir" -name '*.js'  -not ( -path "some_dir/dir_to_exclude1" -prune )  -not ( -path "some_dir/dir_to_exclude2" -prune )  -not ( -path "some_dir/dir_to_exclude3" -prune ) 

    The above patterns are the best because when the -prune option is on with escaped parenthesis as shown above, and when you specify the folder name like that (nothing after the folder name in this case), it excludes both the folder and its contents.

    If you remove the parenthesis and the -prune option, -not -path "./dir_to_exclude" will undesirably exclude only the directory name, but not its contents. If you don’t follow my recommended patterns above, you’d have to use -not -path "./dir_to_exclude" to exclude only the folder name, and -not -path "./dir_to_exclude/*" to exclude only the folder contents, and -not -path "./dir_to_exclude" -not -path "./dir_to_exclude/*" to exclude both.

    Additionally, removing the parenthesis and -prune option from my examples above takes 2x~100x longer. That’s a HUGE speed difference! Using the parenthesis and -prune option causes find to NOT recurse down the excluded directories, whereas find . -not -path "./dir_to_exclude" -not -path "./dir_to_exclude/*" would still waste vast amounts of time recursing down the excluded directory.

    Discussion of nuances and rules of thumb

    When using find:

    1. You must include either a wildcard (*) or the “starting point” path in the -path you are trying to match. Examples:

      1. Match exact paths relative to the “starting point” path by prefixing your -path to match with the “starting point” path:

        # 1. with the "starting point" being the current directory, `.` find . -not -path "./dir_to_exclude/*" # or (same thing) find -not -path "./dir_to_exclude/*" # 2. with the "starting point" being the root dir, `/` find / -not -path "/dir_to_exclude/*" # 3. with the "starting point" being "some_dir" find "some_dir" -not -path "some_dir/dir_to_exclude/*" 

        Again, notice that in all -path matches above, you must explicitly prefix the path with the “starting point” path. Otherwise, you can use a wildcard:

      2. Match wildcard paths to find your -path at any level or sub-directory within your search path. ie: prefix your -path with *. Examples:

        # match "./dir_to_exclude/file1" as well as  # "./another_dir/dir_to_exclude/file1" find . -not -path "*/dir_to_exclude/*" # match "/dir_to_exclude/file1" as well as  # "/another_dir/dir_to_exclude/file1" find / -not -path "*/dir_to_exclude/*" # match "some_dir/dir_to_exclude/file1" as well as  # "some_dir/another_dir/dir_to_exclude/file1" find "some_dir" -not -path "*/dir_to_exclude/*" 

        Again, notice that in all -path matches above, I explictly prefixed the path with the * wildcard char to match at any level.

    2. Use -ipath to do case-insensitive path matches. From man find:

      -ipath pattern Like -path. but the match is case insensitive. 


      # exclude "./dir_to_exclude/*", as well as "./DIR_TO_EXCLUDE/*", and  # "./DiR_To_eXcluDe/*", etc. find . -not -ipath "./dir_to_exclude/*" 
    3. When not using the escaped parenthesis and the -prune option, find will still recurse down the excluded paths, making it as slow as mud. ☹️

    4. When not using the escaped parenthesis and the -prune option, find . -not -path "./dir_to_exclude/*" excludes only the contents of the excluded dir, but NOT the excluded dir itself, and find . -not -path "./dir_to_exclude" excluded only the directory name itself, but NOT the contents (files and folders) within that directory! Use both to exclude both. Examples:

      # exclude the files and folders within the excluded dir, but # leaving "./dir_to_exclude" itself find . -not -path "./dir_to_exclude/*" # exclude the dir name only, but leaving (NOT excluding) all files and # folders within that dir! find . -not -path "./dir_to_exclude" # exclude both the folder itself, as well as its contents find .  -not -path "./dir_to_exclude/*"  -not -path "./dir_to_exclude" 
    5. All of the above examples in this “rules of thumb” section are pure garbage and trash ☹️. You should wrap every single one of them with the escaped parenthesis and the -prune option, like this :

      find . -not ( -path "./dir_to_exclude/*" -prune ) find -not ( -path "./dir_to_exclude/*" -prune ) find / -not ( -path "/dir_to_exclude/*" -prune ) find "some_dir" -not ( -path "some_dir/dir_to_exclude/*" -prune ) find . -not ( -path "*/dir_to_exclude/*" -prune ) find / -not ( -path "*/dir_to_exclude/*" -prune ) find "some_dir" -not ( -path "*/dir_to_exclude/*" -prune ) find . -not ( -ipath "./dir_to_exclude/*" -prune ) find . -not ( -path "./dir_to_exclude/*" -prune ) find . -not ( -path "./dir_to_exclude" -prune ) find .  -not ( -path "./dir_to_exclude/*" -prune )  -not ( -path "./dir_to_exclude" -prune ) 

    The above content is my latest information as of 4 Sept. 2022. The below content is my older answer, which still has a ton of useful information, but doesn’t cover the nuances as well as what I’ve presented above. Read it to gain more knowledge and see some more examples, applying what you learned above to what I present below.

    Generic examples

    Notice that the ./ (or */, see below) before and the /* (or *, but see the caveat below) after the folder name to exclude are required in order to exclude dir_to_exclude, and anything within it!

    Also, for speed, and to not traverse excluded directories, notice the really important escaped grouping parenthesis and the -prune option. Ex: find -not ( -path "*/dir_to_exclude/*" -prune ).

    To see examples of these escaped grouping parenthesis in the manual pages, run man find, and then press / to search. Search for the pattern (, for instance, using the regular expression pattern \(. Press Enter to begin searching the man pages. Press N for “next match” while searching.


    These work:

    # [my favorite #1] exclude contents of `dir_to_exclude` at the search root find -not -path "./dir_to_exclude/*" # exclude all files & folders beginning with the name `dir_to_exclude` at the # search root  find -not -path "./dir_to_exclude*" # [my favorite #2] exclude contents of `dir_to_exclude` at any level within your # search path find -not -path "*/dir_to_exclude/*" # exclude all files & folders beginning with the name `dir_to_exclude` at any # level within your search path find -not -path "*/dir_to_exclude*" # To exclude multiple matching patterns, use `-not -path "*/matching pattern/*"` # multiple times, like this find -not -path "*/dir_to_exclude1/*" -not -path "*/dir_to_exclude2/*" 

    [USE THESE] These work too, and are BETTER because they cause find to NOT unnecessarily traverse down excluded paths!:
    (This makes a huge difference in speed (is 2x~100x faster)! See here and here. You can also search the man find pages locally for the strings ( and ) with the escaped search strings \( and \), respectively).

    find -not ( -path "./dir_to_exclude" -prune ) # works to exclude *both* the  # directory *and* its contents # here, here but does *not* # exclude the contents as well # when the directory name is # written like this in the # examples above find -not ( -path "./dir_to_exclude*" -prune ) find -not ( -path "./dir_to_exclude/*" -prune ) find -not ( -path "*/dir_to_exclude" -prune ) # same note as just above find -not ( -path "*/dir_to_exclude*" -prune ) find -not ( -path "*/dir_to_exclude/*" -prune ) # To exclude multiple matching patterns at once, use the `-not ( ... )`  # pattern multiple times, like this find -not ( -path "*/dir_to_exclude1/*" -prune )  -not ( -path "*/dir_to_exclude2/*" -prune ) 

    …but these do NOT work:

    # These do NOT work! find -not -path "dir_to_exclude" find -not -path "dir_to_exclude/*" find -not -path "./dir_to_exclude" find -not -path "./dir_to_exclude/" 

    The key is that generally, to make it work, you must begin each matching pattern with either ./ or */, and end each matching pattern with either /* or *, depending on what you’re trying to achieve. I say “generally”, because there are two noted exceptions in the -not ( ... )-style section above. You can identify these two exceptions by the comments to the right of them which say: # works here but not above.

    Further Explanation:

    1. [BEST, depending on what you want] This WORKS! Exclude all files and folders inside dir_to_exclude at the root of where you are searching. Note that this excludes all subfiles and subfolders inside dir_to_exclude, but it does NOT exclude the dir_to_exclude dir itself.
      find -not ( -path "./dir_to_exclude/*" -prune ) 
    2. Also exclude the dir_to_exclude dir itself (and any file or folder with a name which begins with these characters). Caveat: this also excludes dir_to_exclude1, dir_to_exclude2, dir_to_exclude_anyTextHere, etc. It excludes ANY file or folder which merely begins with the text dir_to_exclude and is in the root directory of where you’re searching.
      find -not ( -path "./dir_to_exclude*" -prune ) 
    3. [BEST, depending on what you want] to recursively exclude a dir by this name at any level in your search path. Simply add a wildcard * to the front of the path too, rather than using the . to indicate the search root directory.
      find -not ( -path "*/dir_to_exclude/*" -prune ) 
    4. Recursively exclude any file or folder with a name which begins with the characters dir_to_exclude at any level in your search path. (See also the caveat above).
      find -not ( -path "*/dir_to_exclude*" -prune ) 


    In ./, the . at the beginning means “start in the current directory” (or in */, the * is a wildcard to pick up any characters up to this point), and in /* at the end, the * is a wildcard to pick up any characters in the path string after the / character. That means the following:

    1. "./dir_to_exclude/*" matches all subfiles and subfolders within dir_to_exclude in the root search directory (./), but does NOT match the directory itself.
    2. "./dir_to_exclude*" matches all files and folders within the root search directory (./), including dir_to_exclude, as well as all contents within it, but also with the caveat it will match any file or folder name beginning with the characters dir_to_exclude.
    3. "*/dir_to_exclude/*" matches all subfiles and subfolders within dir_to_exclude in any directory at any level in your search path (*/), but does NOT match the directory itself.
    4. "*/dir_to_exclude*" matches all files and folders at any level (*/) within your search path with a name which begins with dir_to_exclude.

    Going further

    From there, I like to pipe to grep to search for certain matching patterns in the paths of interest. Ex: search for any path that is NOT inside the dir_to_exclude directory, and which has desired_file_name.txt in it:

    # Case-sensitive; notice I use `.` instead of `.` when grepping, in order to # search for the literal period (`.`) instead of the regular expression # wildcard char, which is also a period (`.`). find -not ( -path "./dir_to_exclude/*" -prune )  | grep "desired_file_name.txt" # Case-INsensitive (use `-i` with your `grep` search) find -not ( -path "./dir_to_exclude/*" -prune )  | grep -i "desired_file_name.txt" # To make `dir_to_exclude` also case INsensitive, use the `find` `-ipath` option # instead of `-path`: find -not -ipath ( -path "./dir_to_exclude/*" -prune )  | grep -i "desired_file_name.txt" 

    To exclude multiple matching patterns, simply use -not ( -path "*/matching pattern/*" -prune ) multiple times. Ex:

    # Exclude all ".git" and "..git" dirs at any level in your search path find -not ( -path "*/.git/*" -prune ) -not ( -path "*/..git/*" -prune ) 

    I use the above example as part of my sublf alias here (update: that alias is being expanded and moved into a script in this folder here instead). This alias allows me to use the fzf fuzzy finder to quickly search for and open multiple files in Sublime Text. See the links above for the latest version of it.

    alias sublf='FILES_SELECTED="$(find -not ( -path "*/.git/*" -prune )  -not ( -path "*/..git/*" -prune )  | fzf -m)"  && echo "Opening these files in Sublime Text:"  && echo "$FILES_SELECTED"  && subl $(echo "$FILES_SELECTED")' 


    1. [the main answer to this question] How do I exclude a directory when using `find`?

    See also:

    1. [I still need to study and read this]
    2. [my answer] How to store the output of find (a multi-line string list of files) into a bash array

    Keywords: exclude dir in find command; don’t search for path with find; case-insensitive find and grep commands

  8. I prefer the -not notation … it’s more readable:

    find . -name '*.js' -and -not -path directory 
  9. Use the -prune option. So, something like:

    find . -type d -name proc -prune -o -name '*.js' 

    The ‘-type d -name proc -prune’ only look for directories named proc to exclude.
    The ‘-o’ is an ‘OR’ operator.

  10. -prune definitely works and is the best answer because it prevents descending into the dir that you want to exclude. -not -path which still searches the excluded dir, it just doesn’t print the result, which could be an issue if the excluded dir is mounted network volume or you don’t permissions.

    The tricky part is that find is very particular about the order of the arguments, so if you don’t get them just right, your command may not work. The order of arguments is generally as such:

    find {path} {options} {action} 

    {path}: Put all the path related arguments first, like . -path './dir1' -prune -o

    {options}: I have the most success when putting -name, -iname, etc as the last option in this group. E.g. -type f -iname '*.js'

    {action}: You’ll want to add -print when using -prune

    Here’s a working example:

    # setup test mkdir dir1 dir2 dir3 touch dir1/file.txt; touch dir1/file.js touch dir2/file.txt; touch dir2/file.js touch dir3/file.txt; touch dir3/file.js # search for *.js, exclude dir1 find . -path './dir1' -prune -o -type f -iname '*.js' -print # search for *.js, exclude dir1 and dir2 find . ( -path './dir1' -o -path './dir2' ) -prune -o -type f -iname '*.js' -print 
  11. There are plenty of good answers, it just took me some time to understand what each element of the command was for and the logic behind it.

    find . -path ./misc -prune -o -name '*.txt' -print 

    find will start finding files and directories in the current directory, hence the find ..

    The -o option stands for a logical OR and separates the two parts of the command :

    [ -path ./misc -prune ] OR [ -name '*.txt' -print ] 

    Any directory or file that is not the ./misc directory will not pass the first test -path ./misc. But they will be tested against the second expression. If their name corresponds to the pattern *.txt they get printed, because of the -print option.

    When find reaches the ./misc directory, this directory only satisfies the first expression. So the -prune option will be applied to it. It tells the find command to not explore that directory. So any file or directory in ./misc will not even be explored by find, will not be tested against the second part of the expression and will not be printed.

  12. This is the format I used to exclude some paths:

    $ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path" 

    I used this to find all files not in “.*” paths:

    $ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*" 
  13. The -path -prune approach also works with wildcards in the path. Here is a find statement that will find the directories for a git server serving multiple git repositiories leaving out the git internal directories:

    find . -type d  -not ( -path */objects -prune )  -not ( -path */branches -prune )  -not ( -path */refs -prune )  -not ( -path */logs -prune )  -not ( -path */.git -prune )  -not ( -path */info -prune )  -not ( -path */hooks -prune ) 
  14. a good trick for avoiding printing the pruned directories is to use -print (works for -exec as well) after the right side of the -or after -prune. For example, …

    find . -path "*/.*" -prune -or -iname "*.j2" 

    will print the path of all files beneath the current directory with the `.j2″ extension, skipping all hidden directories. Neat. But it will also print the print the full path of each directory one is skipping, as noted above. However, the following does not, …

    find . -path "*/.*" -prune -or -iname "*.j2" -print 

    because logically there’s a hidden -and after the -iname operator and before the -print. This binds it to the right part of the -or clause due to boolean order of operations and associativity. But the docs say there’s a hidden -print if it (or any of its cousins … -print0, etc) is not specified. So why isn’t the left part of the -or printing? Apparently (and I didn’t understand this from my first reading the man page), that is true if there there is no -print -or -exec ANYWHERE, in which case, -print is logically sprinkled around such that everything gets printed. If even ONE print-style operation is expressed in any clause, all those hidden logical ones go away and you get only what you specify. Now frankly, I might have preferred it the other way around, but then a find with only descriptive operators would apparently do nothing, so I guess it makes sense as it is. As mentioned above, this all works with -exec as well, so the following gives a full ls -la listing for each file with the desired extension, but not listing the first level of each hidden directory, …

    find . -path "*/.*" -prune -or -iname "*.j2" -exec ls -la -- {} + 

    For me (and others on this thread), find syntax gets pretty baroque pretty quickly, so I always throw in parens to make SURE I know what binds to what, so I usually create a macro for type-ability and form all such statements as …

    find . ( ( ... description of stuff to avoid ... ) -prune ) -or  ( ... description of stuff I want to find ... [ -exec or -print] ) 

    It’s hard to go wrong by setting up the world into two parts this way. I hope this helps, though it seems unlikely for anyone to read down to the 30+th answer and vote it up, but one can hope. πŸ™‚

  15. If anyone’s researching on how to ignore multiple paths at once. You can use bash arrays (works perfectly on GNU bash, version 4.4.20(1)-release)

    #!/usr/bin/env bash # This script helps ignore unnecessary dir paths while using the find command EXCLUDE_DIRS=( "! -path /*.git/*" "! -path /*go/*" "! -path /*.bundle/*" "! -path /*.cache/*" "! -path /*.local/*" "! -path /*.themes/*" "! -path /*.config/*" "! -path /*.codeintel/*" "! -path /*python2.7/*" "! -path /*python3.6/*" "! -path /*__pycache__/*" ) find $HOME -type f ${EXCLUDE_DIRS[@]} # if you like fzf find $HOME -type f ${EXCLUDE_DIRS[@]} | fzf --height 40% --reverse 

    Also for some reason, you won’t be able to ignore /bin/ directory paths.

  16. To exclude multiple directories:

    find . -name '*.js' -not ( -path "./dir1" -o -path "./dir2/*" ) 

    To add directories, add -o -path "./dirname/*":

    find . -name '*.js' -not ( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*") 

    But maybe you should use a regular expression, if there are many directories to exclude.

  17. find ! -path "dir1" -iname "*.mp3"
  18. find . ( -path '.**/.git' -o -path '.**/.hg' ) -prune -o -name '*.js' -print 

    The example above finds all *.js files under the current directory, excluding folders .git and .hg, does not matter how deep these .git and .hg folders are.

    Note: this also works:

    find . ( -path '.*/.git' -o -path '.*/.hg' ) -prune -o -name '*.js' -print 

    but I prefer the ** notation for consistency with some other tools which would be off topic here.

  19. seems to work the same as
  20. find . -regextype posix-egrep -regex ".*.(js|vue|s?css|php|html|json)$" -and -not -regex ".*/(node_modules|vendor)/.*"
  21. None of previous answers is good on Ubuntu. Try this:

    find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*" 

    I have found this here

  22. You can use the prune option to achieve this. As in for example:

    find ./ -path ./beta/* -prune -o -iname -print 

    Or the inverse grep β€œgrep -v” option:

    find -iname | grep -v beta 

    You can find detailed instructions and examples in Linux find command exclude directories from searching.

  23. find . -name '*.js' -! -name 'glob-for-excluded-dir' -prune 
  24. TLDR: understand your root directories and tailor your search from there, using the -path <excluded_path> -prune -o option. Do not include a trailing / at the end of the excluded path.


    find / -path /mnt -prune -o -name "*libname-server-2.a*" -print

    To effectively use the find I believe that it is imperative to have a good understanding of your file system directory structure. On my home computer I have multi-TB hard drives, with about half of that content backed up using rsnapshot (i.e., rsync). Although backing up to to a physically independent (duplicate) drive, it is mounted under my system root (/) directory: /mnt/Backups/rsnapshot_backups/:

    /mnt/Backups/ └── rsnapshot_backups/ β”œβ”€β”€ hourly.0/ β”œβ”€β”€ hourly.1/ β”œβ”€β”€ ... β”œβ”€β”€ daily.0/ β”œβ”€β”€ daily.1/ β”œβ”€β”€ ... β”œβ”€β”€ weekly.0/ β”œβ”€β”€ weekly.1/ β”œβ”€β”€ ... β”œβ”€β”€ monthly.0/ β”œβ”€β”€ monthly.1/ └── ... 

    The /mnt/Backups/rsnapshot_backups/ directory currently occupies ~2.9 TB, with ~60M files and folders; simply traversing those contents takes time:

    ## As sudo (#), to avoid numerous "Permission denied" warnings: time find /mnt/Backups/rsnapshot_backups | wc -l 60314138 ## 60.3M files, folders 34:07.30 ## 34 min time du /mnt/Backups/rsnapshot_backups -d 0 3112240160 /mnt/Backups/rsnapshot_backups ## 3.1 TB 33:51.88 ## 34 min time rsnapshot du ## << more accurate re: rsnapshot footprint 2.9T /mnt/Backups/rsnapshot_backups/hourly.0/ 4.1G /mnt/Backups/rsnapshot_backups/hourly.1/ ... 4.7G /mnt/Backups/rsnapshot_backups/weekly.3/ 2.9T total ## 2.9 TB, per sudo rsnapshot du (more accurate) 2:34:54 ## 2 hr 35 min 

    Thus, anytime I need to search for a file on my / (root) partition, I need to deal with (avoid if possible) traversing my backups partition.


    Among the approached variously suggested in this thread (How to exclude a directory in find . command), I find that searches using the accepted answer are much faster — with caveats.

    Solution 1

    Let’s say I want to find the system file libname-server-2.a, but I do not want to search through my rsnapshot backups. To quickly find a system file, use the exclude path /mnt (i.e., use /mnt, not /mnt/, or /mnt/Backups, or …):

    ## As sudo (#), to avoid numerous "Permission denied" warnings: time find / -path /mnt -prune -o -name "*libname-server-2.a*" -print /usr/lib/libname-server-2.a real 0m8.644s ## 8.6 sec <<< NOTE! user 0m1.669s sys 0m2.466s ## As regular user (victoria); I also use an alternate timing mechanism, as ## here I am using 2>/dev/null to suppress "Permission denied" warnings: $ START="$(date +"%s")" && find 2>/dev/null / -path /mnt -prune -o  -name "*libname-server-2.a*" -print; END="$(date +"%s")";  TIME="$((END - START))"; printf 'find command took %s secn' "$TIME" /usr/lib/libname-server-2.a find command took 3 sec ## ~3 sec <<< NOTE! 

    … finds that file in just a few seconds, while this take much longer (appearing to recurse through all of the “excluded” directories):

    ## As sudo (#), to avoid numerous "Permission denied" warnings: time find / -path /mnt/ -prune -o -name "*libname-server-2.a*" -print find: warning: -path /mnt/ will not match anything because it ends with /. /usr/lib/libname-server-2.a real 33m10.658s ## 33 min 11 sec (~231-663x slower!) user 1m43.142s sys 2m22.666s ## As regular user (victoria); I also use an alternate timing mechanism, as ## here I am using 2>/dev/null to suppress "Permission denied" warnings: $ START="$(date +"%s")" && find 2>/dev/null / -path /mnt/ -prune -o  -name "*libname-server-2.a*" -print; END="$(date +"%s")";  TIME="$((END - START))"; printf 'find command took %s secn' "$TIME" /usr/lib/libname-server-2.a find command took 1775 sec ## 29.6 min 

    Solution 2

    The other solution offered in this thread (SO#4210042) also performs poorly:

    ## As sudo (#), to avoid numerous "Permission denied" warnings: time find / -name "*libname-server-2.a*" -not -path "/mnt" /usr/lib/libname-server-2.a real 33m37.911s ## 33 min 38 sec (~235x slower) user 1m45.134s sys 2m31.846s time find / -name "*libname-server-2.a*" -not -path "/mnt/*" /usr/lib/libname-server-2.a real 33m11.208s ## 33 min 11 sec user 1m22.185s sys 2m29.962s 


    Use the approach illustrated in “Solution 1

    find / -path /mnt -prune -o -name "*libname-server-2.a*" -print 


    ... -path <excluded_path> -prune -o ... 

    noting that whenever you add the trailing / to the excluded path, the find command then recursively enters (all those) /mnt/* directories — which in my case, because of the /mnt/Backups/rsnapshot_backups/* subdirectories, additionally includes ~2.9 TB of files to search! By not appending a trailing / the search should complete almost immediately (within seconds).

    “Solution 2” (... -not -path <exclude path> ...) likewise appears to recursively search through the excluded directories — not returning excluded matches, but unnecessarily consuming that search time.

    Searching within those rsnapshot backups:

    To find a file in one of my hourly/daily/weekly/monthly rsnapshot backups):

    $ START="$(date +"%s")" && find 2>/dev/null /mnt/Backups/rsnapshot_backups/daily.0 -name '*04t8ugijrlkj.jpg'; END="$(date +"%s")"; TIME="$((END - START))"; printf 'find command took %s secn' "$TIME" /mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg find command took 312 sec ## 5.2 minutes: despite apparent rsnapshot size ## (~4 GB), it is in fact searching through ~2.9 TB) 

    Excluding a nested directory:

    Here, I want to exclude a nested directory, e.g. /mnt/Vancouver/projects/ie/claws/data/* when searching from /mnt/Vancouver/projects/:

    $ time find . -iname '*test_file*' ./ie/claws/data/test_file ./ie/claws/test_file 0:01.97 $ time find . -path '*/data' -prune -o -iname '*test_file*' -print ./ie/claws/test_file 0:00.07 

    Aside: Adding -print at the end of the command suppresses the printout of the excluded directory:

    $ find / -path /mnt -prune -o -name "*libname-server-2.a*" /mnt /usr/lib/libname-server-2.a $ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print /usr/lib/libname-server-2.a 
  25. The following commands works:

    find . -path ./.git -prune -o -print 

    If You have a problem with find, use the -D tree option to view the expression analysis information.

    find -D tree . -path ./.git -prune -o -print 

    Or the -D all, to see all the execution information.

    find -D all . -path ./.git -prune -o -print 
  26. This is suitable for me on a Mac:

    find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune 

    It will exclude vendor and app/cache dir for search name which suffixed with php.

  27. If you are looking for a high-performance answer, then it is:

    find . -type d -name node_modules -prune -false -o -type f 

    Use -false to exclude node_modules itself.

    It will be 3x faster than -not -path approach in a directory with 10000 files in node_modules.

    find . -type f -not -path '*node_modules*' 

    And if node_modules has more files, you shall get a much higher performance.

  28. I was using find to provide a list of files for xgettext, and wanted to omit a specific directory and its contents. I tried many permutations of -path combined with -prune but was unable to fully exclude the directory which I wanted gone.

    Although I was able to ignore the contents of the directory which I wanted ignored, find then returned the directory itself as one of the results, which caused xgettext to crash as a result (doesn’t accept directories; only files).

    My solution was to simply use grep -v to skip the directory that I didn’t want in the results:

    find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext 

    Whether or not there is an argument for find that will work 100%, I cannot say for certain. Using grep was a quick and easy solution after some headache.

  29. For those of you on older versions of UNIX who cannot use -path or -not

    Tested on SunOS 5.10 bash 3.2 and SunOS 5.11 bash 4.4

    find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f 
  30. how-to-use-prune-option-of-find-in-sh is an excellent answer by Laurence Gonsalves on how -prune works.

    And here is the generic solution:

    find /path/to/search  -type d  ( -path /path/to/search/exclude_me  -o  -name exclude_me_too_anywhere  )  -prune  -o  -type f -name '*.js' -print 

    To avoid typing /path/to/seach/ multiple times, wrap the find in a pushd .. popd pair.

    pushd /path/to/search;  find .  -type d  ( -path ./exclude_me  -o  -name exclude_me_too_anywhere  )  -prune  -o  -type f -name '*.js' -print;  popd 
  31. I tried command above, but none of those using “-prune” works for me. Eventually I tried this out with command below:

    find . ( -name "*" ) -prune -a ! -name "directory" 
  32. For what I needed it worked like this, finding landscape.jpg in all server starting from root and excluding the search in /var directory:

    find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg

    find / -maxdepth 1 -type d lists all directories in /

    grep -v /var excludes `/var’ from the list

    xargs -I '{}' find '{}' -name landscape.jpg execute any command, like find with each directory/result from list

  33. I consider myself a bash junkie, BUT … for the last 2 years have not find a single bash user friendly solution for this one. By “user-friendly” I mean just a single call away, which does not require me to remember complicated syntax + I can use the same find syntax as before , so the following solution works best for those ^^^

    Copy paste this one in your shell and source the ~/.bash_aliases :

    cat << "EOF" >> ~/.bash_aliases # usage: source ~/.bash_aliases , instead of find type findd + rest of syntax findd(){ dir=$1; shift ; find $dir -not -path "*/node_modules/*" -not -path "*/build/*"  -not -path "*/.cache/*" -not -path "*/.git/*" -not -path "*/venv/*" [email protected] } EOF 

    Of course in order to add or remove dirs to exclude you would have to edit this alias func with your dirs of choice …

  34. Another example when using multiple patterns -o -name

    To search in the root directory / for all *.tpl, *.tf files, excluding files which reside in /src/.terraform/ and /code/.

    $ find / -type f ( -name '*.tf' -o -name '*.tpl' )  -and ( -not -path '/src/.terraform/*' -and -not -path '/code/*' ) /src/ /src/nodegroup-infra.tpl /src/ 

    I tested the above command with hyperfine; The test was conducted on a system with 3k directories and 12k files. I think it’s fair to say that it’s fast enough ~70ms

    Benchmark #1: ./ Time (mean Β± Οƒ): 69.2 ms Β± 1.4 ms [User: 22.6 ms, System: 43.6 ms] Range (min … max): 66.4 ms … 72.2 ms 42 runs 

    Sample Directory Structure

    /code/ directory tree

    bash-5.0# tree /code /code β”œβ”€β”€ β”œβ”€β”€ β”œβ”€β”€ nodegroup-infra.tpl β”œβ”€β”€ └── 0 directories, 5 files 

    /src/ directory tree

    bash-5.0# tree /src /src β”œβ”€β”€ Dockerfile β”œβ”€β”€ β”œβ”€β”€ β”œβ”€β”€ nodegroup-infra.tpl β”œβ”€β”€ terraform.tfstate β”œβ”€β”€ terraform.tfstate.backup └── 0 directories, 7 files 

    / root directory tree summary

    $ tree / ... 3382 directories, 12164 files 
  35. find -type f -not -name .directoryname -printf "%fn"
  36. If anyone looking to add find command inside Makefile, here is how we exclude directory

    ! -path "*/directoryName/*"

    Below is the example to format all golang file excluding protobuf go files and all files under vendor directory:

    find . ! -name '*.pb.go' -name '*.go' ! -path "*/vendor/*" -exec gofmt -s -w '{}' + 
  37. This works because find TESTS the files for the pattern*foo*“:

    find ! -path "dir1" ! -path "dir2" -name "*foo*" 

    but it does NOT work if you don’t use a pattern (find does not TEST the file). So find makes no use of its former evaluated “true” & “false” bools. Example for not working use case with above notation:

    find ! -path "dir1" ! -path "dir2" -type f 

    There is no find TESTING! So if you need to find files without any pattern matching use the -prune. Also, by the use of prune find is always faster while it really skips that directories instead of matching it or better not matching it. So in that case use something like:

    find dir -not ( -path "dir1" -prune ) -not ( -path "dir2" -prune ) -type f 


    find dir -not ( -path "dir1" -o -path "dir2" -prune ) -type f 


  38. I found the functions name in C sources files exclude *.o and exclude *.swp and exclude (not regular file) and exclude dir output with this command:

    find . ( ! -path "./output/*" ) -a ( -type f ) -a ( ! -name '*.o' ) -a ( ! -name '*.swp' ) | xargs grep -n soc_attach 
  39. For FreeBSD users:

     find . -name '*.js' -not -path '*exclude/this/dir*' 
  40. Better use the exec action than the for loop:

    find . -path "./dirtoexclude" -prune  -o -exec java -jar config/yuicompressor-2.4.2.jar --type js '{}' -o '{}' ; 

    The exec ... '{}' ... '{}' ; will be executed once for every matching file, replacing the braces '{}' with the current file name.

    Notice that the braces are enclosed in single quote marks to protect them from interpretation as shell script punctuation*.


    * From the EXAMPLES section of the find (GNU findutils) 4.4.2 man page

  41. If search directories has pattern (in my case most of the times); you can simply do it like below:

    find ./n* -name "*.tcl" 

    In above example; it searches in all the sub-directories starting with “n”.

  42. I have found the suggestions on this page and a lot of other pages just do not work on my Mac OS X system. However, I have found a variation which does work for me.

    The big idea is to search the Macintosh HD but avoid traversing all the external volumes, which are mostly Time Machine backups, image backups, mounted shares, and archives, but without having to unmount them all, which is often impractical.

    Here is my working script, which I have named “findit”.

    #!/usr/bin/env bash # inspired by Danile C. Sobral # using special syntax to avoid traversing.  # However, logic is refactored because the Sobral version still traverses  # everything on my system echo ============================ echo find - from cwd, omitting external volumes date echo Enter sudo password if requested sudo find . -not (  -path ./Volumes/Archive -prune -o  -path ./Volumes/Boot OS X -prune -o  -path ./Volumes/C  -path ./Volumes/Data -prune -o  -path ./Volumes/jas -prune -o  -path ./Volumes/Recovery HD -prune -o  -path ./Volumes/Time Machine Backups -prune -o  -path ./Volumes/SuperDuper Image -prune -o  -path ./Volumes/userland -prune  ) -name "$1" -print date echo ============================ iMac2:~ jas$ 

    The various paths have to do with external archive volumes, Time Machine, Virtual Machines, other mounted servers, and so on. Some of the volume names have spaces in them.

    A good test run is “findit index.php”, because that file occurs in many places on my system. With this script, it takes about 10 minutes to search the main hard drive. Without those exclusions, it takes many hours.

  43. Not sure if this would cover all edge cases, but following would be pretty straight forward and simple to try:

    ls -1|grep -v -e ddl -e docs| xargs rm -rf

    This should remove all files/directories from the current directory excpet ‘ddls’ and ‘docs’.

  44. Instead of:

    for file in $(find . -name '*.js') do java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file done 

    …and since you don’t define which subdirectory you want to exclude, you could use:

    for file in $(find *.js -maxdepth 0 -name '*.js') do java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file done 

    This syntax will exclude all subdirectories.

    Take a look at the example below: under my tmp directory I have an huge “archive” subdirectory which contains 17000-4640=12360 files. And this directory is located on a slow NFS. While the 1st syntax scans the “archive” subdirectory and performs poorly, the 2nd syntax only scans the “*pdf” files contained in my current dir and performs… not that bad.

    [tmp]$ time (find . -name "*pdf" | wc -l) 17000 real 0m40.479s user 0m0.423s sys 0m5.606s [tmp]$ time (find *pdf -maxdepth 0 -name "*pdf" | wc -l) 4640 real 0m7.778s user 0m0.113s sys 0m1.136s 

    That 2nd syntax is quite interesting: in the following example I want to check if file or60runm50958.pdf exists and is more than 20 minutes old. See for yourself how the 2nd syntax is more efficient. This is because it avoids scanning the archive subdirectory.

    [tmp]$ time find . -name or60runm50958.pdf -mmin +20 ./or60runm50958.pdf real 0m51.145s user 0m0.529s sys 0m6.243s [tmp]$ time find or60runm50958.pdf -maxdepth 0 -name or60runm50958.pdf -mmin +20 or60runm50958.pdf real 0m0.004s user 0m0.000s sys 0m0.002s 
  45. - ... 2791037 Jun 2 2011 foo.jpg - ... 1284734651 MΓ€r 10 16:16 foo.tar.gz - ... 0 MΓ€r 10 15:28 foo.txt d ... 4096 MΓ€r 3 17:12 HE d ... 4096 MΓ€r 3 17:21 KU d ... 4096 MΓ€r 3 17:17 LE d ... 0 MΓ€r 3 17:14 NO d ... 0 MΓ€r 3 17:15 SE d ... 0 MΓ€r 3 17:13 SP d ... 0 MΓ€r 3 17:14 TE d ... 0 MΓ€r 3 19:20 UN
  46. #find command in linux def : find command used to locate /search files in unix /linux system , find search for files in a directory hierarchy 
    1)exec Show diagnostic information relating to -exec, -execdir, -ok and -okdir 2)-options -H =do not follow symoblic links while except while procesing . -L = follow symbolic links -P =never follow symbolic links -type c File is of type c: b block (buffered) special c character (unbuffered) special d directory p named pipe (FIFO) f regular file l symbolic link; this is never true if the -L option or the -follow option is in effect, unless the symbolic link is broken. If you want to search for symbolic links when -L is in effect, use -xtype. s socket D door (Solaris) -Delete Delete files; true if removal succeeded. If the removal failed, an error message is issued. If -delete #fails, find's exit status will be nonzero (when it eventually exits). find /home/mohan/a -mindepth 3 -maxdepth 3 -type f -name "*.txt" |xargs rm -rf find -type d -name find -type f -Name find /path/ -type f -iname (i is case insenstive) #find directores a/b/c and only delete c directory inside have "*.txt " find /home/mohan/a -mindepth 3 -maxdepth 3 -type f -name "*.txt" |xargs rm -rf find /home/mohan/a -mindepth 3 -maxdepath 3 -type f -name "*.txt" -delete #delete particular directory have empty file and only we can delete empty files find /home/mohan -type f -name "*.txt" -empty -DELETE #find multiple files and also find empty files find /home/mohan -type f ( -name "*.sh" -o -name "*.txt" ) -empty #delete empty files two or more Files find /home/mohan -type f ( -nmae "*.sh" -o -name "*.txt" ) -empty -delete #How to append contents of multiple files into one file find . -type f -name '*.txt' -exec cat {} + >> output.file #last modified files finding using less than 1 min (-n) ls -lrth|find . -type f -mmin -1 #last modified files more than 1 min (+n) ls -lrth|find . -type f -mmin +1 #last modified files exactly one mins find . -type f -mmin 1 last modifiedfiles exactly in one day by using command (-mtime) find . -type f -mtime 10 #last modified more than 10 days find . -type f -mtime +10 #last modified less than 10 days find . -type f -mtime -10 #How to Find Modified Files and Folders Starting from a Given Date to the Latest Date find . -type f -newermt "17-11-2020" #How to Find a List of β€œsh” Extension Files Accessed in the Last 30 Days--- -matdimtype ls -lrt|find . -type f -iname ".sh" -atime -30 #How to Find a List of Files Created Today, -1 means less than min, ls -lrt | find . -type f -ctime -1 -ls 

Tasg: linux, shell

Answer Link
  • Unable to run NoraUI mvn verify goal
  • Unable to run my app on emulator in VS Code
  • Unable to run multiple instances of libVLC(MobileVLCKit) in IOS via flutter framework
  • Unable to run make on griddb source on ubuntu 20.04 (building from source)
  • Unable to run latexindent macOS Monterey 12.0.1
  • Unable to run kotlinc-native command
  • Unable to run JUnit Test… Java.lang.ExceptionInInitializerError (Android Studio)
  • Unable to run java with -Xmx > 966m
  • Unable to run ionic cap run android from wsl2 inorder to start android emulator
  • Unable to run Intel HAXM installer: Cannot start process, the working directory does not exist
  • fs
  • Unable to run Google Analytics sample code
  • unable to run flutter run after upgarding to flutter 2.8.0 from 2.5.3
  • Unable to run Django with PostgreSQL in Docker
  • Unable to Run Container Using testcontainers
  • Unable to run ClojureScript Hello World program, Error building classpath. Error reading edn.
  • unable to run client command for apache karaf 4.3.3 through remote server
  • Unable to run c program 2nd time using eclipse
  • unable to run c++ in visual studio code on m1 chipset
  • Unable to run Android Instrumented Tests
  • Unable to run adb, check your Android SDK installation and ANDROID_SDK_ROOT environment variable: …AndroidSdkplatform-toolsadb.exe
  • Unable to run a singlespecific .spec.ts file through angular cli using ng test –include option
  • Unable to run a Mango query
  • Unable to return response back to view in laravel from package
  • Unable to return object reference in std::optional
  • Unable to return NULL in a function that expects an integer return type
  • Unable to return correct change in JavaScript Cash Register
  • Unable to retrieve version information from Elasticsearch nodes. Request timed out
  • Unable to retrieve values from Axios Response data
  • Unable to retrieve dotenv JWT secret Error: secretOrPrivateKey must have a value
  • Unable to resolve your shell environment
  • Unable to resolve token for FCM while implementing Push notification for Xamarin
  • Unable to resolve the request yii
  • Unable to resolve service for type Swashbuckle.AspNetCore.Swagger.ISwaggerProvider
  • Unable to resolve service for type Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger