0

Consider following directory structure:

$ find m
m
m/f.sh
m/.a

I want to find hidden files in non-hidden directories with:

find . -not -path "*/.*" -and -name "*.*"
.
./m/f.sh

but only f.sh is found, where I expect to find also .a. When searching without -not -path part, all hidden files are found:

find . -name "*.*"
./m/f.sh
./m/.a

How can I specify to search non-hidden directories, but match also hidden files?

To clarify:

  • ./non-hidden-dir/.hidden-dir/.hidden-file should be found.
  • ./.hidden-dir/non-hidden-dir/.hidden-file should not be found.
4
  • @KamilMaciorowski I think it complicates the question. I simply want to find hidden files in non-hidden directories. When searched without -not -path part but with "." pattern for -name hidden files are displayed as well. Please see edited question.
    – l00p
    Commented Nov 21, 2020 at 8:34
  • You're not helping me helping you. Please answer "yes" or "no": (1) Should ./non-hidden-dir/.hidden-dir/.hidden-file be found? (2) Should ./.hidden-dir/non-hidden-dir/.hidden-file be found? Commented Nov 21, 2020 at 8:54
  • @KamilMaciorowski 1) yes; 2) no;
    – l00p
    Commented Nov 21, 2020 at 9:31
  • So the top level subdirectory is the one that counts. Somewhat surprising but so be it. Commented Nov 21, 2020 at 9:36

1 Answer 1

1

About what you tried:

  • -not -path "*/.*" evaluates to false for any pathname containing /.. It excludes all hidden files and prunes all hidden subdirectories (not like -prune because their content will be tested, still the test will always turn out false).
  • -name "*.*" evaluates to true for any basename containing ., regardless if the dot appears in front (.a) or somewhere else (f.sh).

It seems you want to prune top level directories that are hidden. Everywhere else you want to find hidden files. So this:

find . -path './.*' -prune -o -name '.*'

The above code effectively treats . as non-hidden and it uses the POSIX definition of "file" which says a directory is also a file. If you meant "hidden regular files" then the code should be:

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

Notes:

  • -not and -and you used are not portable; the portable equivalents are ! and -a respectively (and you may or may not omit -a).
  • This answer of mine may be helpful in learning how find works.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .