27

How can I use the find command to locate directories that do NOT contain a particular file? E.g., if I have bunch of directories that should be under revision control, can I search and find the ones that do not have a .git sub-directory? Or, my project specifies that all modules should have a utilities.py file; how do I search to find which sub-directories do not yet have the required file?

ChrisDR
  • 487

1 Answers1

31

The solution that might work for your case is,

find . -type d '!' -exec test -e "{}/utilities.py" ';' -print

Testing

  1. I created 4 sub directories named dir1, dir2, dir3 and dir with spaces. I wanted to test if this handles spaces equally well which is why I created a directory with spaces in its name.
  2. I created files file1, file2, file3 and file4 in dir2 and dir3.
  3. In dir1, I created file1, file2, file3.
  4. In dir with spaces, I created a file named file with spaces.
  5. Now, I execute my find command as,

    find . -type d '!' -exec test -e "{}/file with spaces" ';' -print
    
  6. The output I get is,

    .
    ./dir1
    ./dir2
    ./dir3
    
  7. As expected, since the directory dir with spaces contains the file named file with spaces it is not listed in the output. If I change the find command to have file4 in it, the output I get is,

    .
    ./dir with spaces
    ./dir1
    

EDIT

However, the above approach doesn't seem to work if we have nested subdirectories and the file in the final level. So to overcome such scenarios, you could modify your find to something like discussed over here.

find . -type f -not -name 'utilities.py' -exec dirname {} \; | sort -u

As Gilles suggests in his comments,

For .git, it would be more useful to skip directories that have a parent containing .git. You can do this by adding a -prune in the right place:

find . -type d -exec test -e "{}/.git" ';' -prune -o -print
Ramesh
  • 39,297
  • This will list all files and directories except utilities.py, without telling me which DIRECTORIES do NOT have that file in them. – ChrisDR Sep 29 '14 at 15:19
  • 1
    @ChrisDR, please see the updates. – Ramesh Sep 29 '14 at 15:27
  • +1 but I'd delete the first suggestion since it does not help the OP. – terdon Sep 29 '14 at 15:53
  • @terdon, thanks. I deleted it. But it seems the latest edit is something what the OP might be interested in since it deals with the subdirectories as well. – Ramesh Sep 29 '14 at 15:55
  • 3
    For .git, it would be more useful to skip directories that have a parent containing .git. You can do this by adding a -prune in the right place: find . -type d -exec test -e "{}/.git" ';' -prune -o -print – Gilles 'SO- stop being evil' Sep 29 '14 at 23:00
  • @Gnouc, I got it from another source which I have referenced. So, I am not sure about it. – Ramesh Sep 30 '14 at 01:38
  • If you feel it is not needed, I will go ahead and remove it after I test it once I get back home. :) – Ramesh Sep 30 '14 at 01:38