Starting from (notice the wildcards before and after "some text")

find . -type f -name '*some text*'

how can one exclude/ignore all hidden files and directories?

I've already been googling for far too long, came across some -prune and ! (exclamation mark) parameters, but no fitting (and parsimonious) example which just worked.

Piping | to grep would be an option and I'd also welcome examples of that; but primarily I'm interested in a brief one-liner (or a couple of stand-alone one-liners, illustrating different ways of achieving the same command-line goal) just using find.

ps: Find files in linux and exclude specific directories seems closely related, but a) is not accepted yet and b) is related-but-different-and-distinct, but c) may provide inspiration and help pinpoint the confusion!

Edit

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.

share|improve this question
    
Doesn't help with what you asked in your edit but take a look at my question and its answer here: unix.stackexchange.com/q/69164/15760 and also the link in the answer. – user25656 Mar 26 '13 at 6:25
    

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 (it has to be escaped to avoid special meaning), 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
share|improve this answer
    
Note with the last one that you need that -print at the end! Also, not sure if -name '\.*' would be more efficient instead of -path` (because the path is searching subpaths, but these will be pruned out) – artfulrobot Apr 29 '14 at 11:18
    
What's the special meaning of . in this context? – frostschutz Jan 15 '15 at 15:40
    
@frostschutz The dot after find means the current directory: find will look at all files and directories under the current directory. The argument after path is a regular expression, where a dot would normally means "any character", to make it mean a literal dot we have to escape it with a backslash. The argument after -name isn't a regular expression, but it expands wildcards like ? and * like a shell does. – Flimm Jan 15 '15 at 17:23
1  
@frostschutz Actually, come to think of it, I may be wrong about . having special meaning. – Flimm Aug 5 '16 at 13:00
    
@Flimm yup, no need to escape .. As far as I'm aware, only these need to be escaped: *, ?, and []. – 10basetom Feb 15 '17 at 9:16

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.
share|improve this answer
    
Please explain / elaborate on "alarmingly complicated"; the answers already given and your answer seem to give evidence to the contrary...? – nutty about natty Mar 24 '16 at 22:13
2  
"alarmingly complicated" is probably excessive. I reworded the answer to get to the point. I think the answer I posted is difficult to understand and is hard to see without a very careful reading of the man page. If you are only using GNU find then there are more possible solutions. – eradman Mar 28 '16 at 14:50
    
-o ... -print is helpful. For my use, I now have find ... '!' -name . -name '.*' -prune -o ... -print, which was more convenient than including $PWD. – Roger Pate Aug 24 '16 at 19:28
    
$PWD should probably be quoted, in case it has a space in it. – Daniel James Apr 19 '17 at 11:37
    
@DanielJames indeed, $PWD should be quoted – eradman Apr 19 '17 at 14:31
find $DIR -not -path '*/\.*' -type f \( ! -iname ".*" \)

Excludes all hidden directories, and hidden files under $DIR

share|improve this answer
    
This is the perfect answer. It recursively finds all files but excludes line items for directories and hidden files. Thanks! – KyleFarris Oct 8 '15 at 5:41
up vote 3 down vote accepted

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.

share|improve this answer
    
Similar, but for only the current folder: find . \( ! -regex './\..*' \) -type f -maxdepth 1 -print – phyatt Mar 22 '17 at 15:44

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
share|improve this answer
5  
You don't need ls for that! echo **/*foo* – Kevin Cox Mar 1 '16 at 3:25
    
@kenorb (and @kevin-cox). Could you be a bit more verbose? Why would globstar ( = * ) work here and how? What does the slash / do? – nutty about natty May 18 '17 at 19:47
    
@nuttyaboutnatty / means folder, it separates directories from the filename. * basically represents everything. – kenorb May 18 '17 at 20:14
    
@kenorb yes-but: how does that one-liner help with the original question? – nutty about natty May 19 '17 at 14:17
1  
@nuttyaboutnatty Clarified and added example. It helps by finding files ignoring the hidden one. – kenorb May 19 '17 at 16:40

find has neat logic switches such as -and and -not you can use them to your advantage to find a matching file with two rules like so:

$ touch non_hidden_file.txt .hidden_file.txt somethings/.another_hidden_file.txt                                                 

$ find . -type f -name '*hidden_file*' -and \( -not -name ".*" \)                            
./non_hidden_file.txt

As you can see, find uses two rules -name '*hidden_file*' and -and \( -not -name ".*" \) to find those filenames that match both conditions - filename with hidden_file in it but without leading dot. Note the slashes in front of parenthesis - they are used to define parenthesis as find arguments rather defining a subshell (which is what parenthesis mean otherwise without slashes)

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.