List all directories that do NOT have a file with a given file name inside

Assuming a find implementation like GNU find that accepts a {} embedded in an argument to -exec:

$ find . -type d \! -exec test -e '{}/README' \; -print

or, without the problematic embedding:

$ find . -type d ! -exec sh -c 'test -e "$1"/README' sh {} \; -print

Example

Here directories 1/1 through 5/5 have a README, the other dirs are empty.

$ tree 
.
|-- 1
|   `-- 1
|       `-- README
|-- 10
|   `-- 10
|-- 2
|   `-- 2
|       `-- README
|-- 3
|   `-- 3
|       `-- README
|-- 4
|   `-- 4
|       `-- README
|-- 5
|   `-- 5
|       `-- README
|-- 6
|   `-- 6
|-- 7
|   `-- 7
|-- 8
|   `-- 8
`-- 9
    `-- 9

Now when we run this version of our find command:

$ find . -type d \! -exec test -e '{}/README' \; -print
.
./10
./10/10
./7
./7/7
./9
./9/9
./6
./6/6
./5
./8
./8/8
./4
./1
./3
./2

References

  • Exclude directories in find that don't contain a specific filename?

No need for find. Just use the shell:

for d in */; do [ -f "$d"README ] || printf '%s\n' "$d"; done
c/

If you need it to be recursive, you can use (for bash, zsh can do this by default, use set -o globstar in ksh93):

shopt -s globstar
for d in **/; do [ -f "$d"README ] || printf '%s\n' "$d"; done

(note that dot-files are excluded by default).


You can use the -exec option of find to check for the file, and then print all results for which the check fails.

find /path/to/base -mindepth 1 -maxdepth 1 -type d -exec test -e {}/README \; -o -print