How to exclude/ignore hidden files and directories in a wildcard-embedded "find" search?

Solution 1:

This prints all files that are descendants of your directory, skipping hidden files and directories:

find . -not -path '*/.*'

So if you're looking for a file with some text in its name, and you want to skip hidden files and directories, run:

find . -not -path '*/.*' -type f -name '*some text*'

Explanation:

The -path option runs checks a pattern against the entire path string. * is a wildcard, / is a directory separator, . is a dot (hidden filenames start with a dot on Linux), and * is another wildcard. -not means don't select files that match this test.

I don't think that find is smart enough to avoid recursively searching hidden directories in the previous command, so if you need speed, use -prune instead, like this:

 find . -type d -path '*/.*' -prune -o -not -name '.*' -type f -name '*some text*' -print

Solution 2:

This is one of the few means of excludes dot-files that also works correctly on BSD, Mac and Linux:

find "$PWD" -name ".*" -prune -o -print
  • $PWD print the full path to the current directory so that the path does not start with ./
  • -name ".*" -prune matches any files or directories that start with a dot and then don't descend
  • -o -print means print the file name if the previous expression did not match anything. Using -print or -print0 causes all other expressions to not print by default.

Solution 3:

find $DIR -not -path '*/\.*' -type f \( ! -iname ".*" \)

Excludes all hidden directories, and hidden files under $DIR

Solution 4:

You don't have to use find for that. Just use globstar in shell it-self, like:

echo **/*foo*

or:

ls **/*foo*

where **/ represents any folder recursively and *foo* any file which has foo in its name.

By default using ls will print file names excluding hidden files and directories.

If you don't have globbing enabled, do it by shopt -s globstar.

Note: A new globbing option works in Bash 4, zsh and similar shells.


Example:

$ mkdir -vp a/b/c/d
mkdir: created directory 'a'
mkdir: created directory 'a/b'
mkdir: created directory 'a/b/c'
mkdir: created directory 'a/b/c/d'
$ touch a/b/c/d/foo a/b/c/d/bar  a/b/c/d/.foo_hidden a/b/c/d/foo_not_hidden
$ echo **/*foo*
a/b/c/d/foo  a/b/c/d/foo_not_hidden

Solution 5:

The answer I originally posted as an "edit" to my original question above:

find . \( ! -regex '.*/\..*' \) -type f -name "whatever", works. The regex looks for "anything, then a slash, then a dot, then anything" (i.e. all hidden files and folders including their subfolders), and the "!" negates the regex.