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.