Jay Taylor's notes

back to listing index

Use GNU find to show only the leaf directories

[web search]
Original source (stackoverflow.com)
Tags: linux filesystem command-line leaf-nodes stackoverflow.com
Clipped on: 2018-08-17
Join us in building a kind, collaborative learning community via our updated Code of Conduct.

I'm trying to use GNU find to find only the directories that contain no other directories, but may or may not contain regular files.

My best guess so far has been:

find dir -type d \( -not -exec ls -dA ';' \)

but this just gets me a long list of "."

Thanks!

asked Nov 24 '10 at 17:40
Thomas G Henry
4,31972229
up vote 63 down vote accepted

You can use -links if your filesystem is POSIX compliant (ie, a directory has a link for each subdirectory in it, a link from its parent and a link to self, thus a count of 2 link if it has no subdirectories).

The following command should do what you want:

find dir -type d -links 2

However, it does not seems to work on Mac OS X (as @Piotr mentionned). Here is another version that is slower, but does work on Mac OS X. It is based on his version, with correction to handle whitespace in directory names:

find . -type d -exec sh -c '(ls -p "{}"|grep />/dev/null)||echo "{}"' \;
answered Nov 24 '10 at 17:46
Sylvain Defresne
30.6k65879

I just found another solution to this that works on both Linux & macOS (without find -exec)!

It involves sort (twice) and awk:

find dir -type d | sort -r | awk 'a!~"^"$0{a=$0;print}' | sort

Explanation:

  1. sort the find output in reverse order

    • now you have subdirectories appear first, then their parents
  2. use awk to omit lines if the current line is a prefix of the previous line

    • (this command is from the answer here)
    • now you eliminated "all parent directories" (you're left with parent dirs)
  3. sort them (so it looks like the normal find output)
  4. Voila! Fast and portable.
answered May 27 at 3:59

@Sylvian solution didn't work for me on mac os x for some obscure reason. So I've came up with a bit more direct solution. Hope this will help someone:

find . -type d  -print0 | xargs -0 -IXXX sh -c '(ls -p XXX | grep / >/dev/null) || echo XXX' ;

Explanation:

  • ls -p ends directories with '/'
  • so (ls -p XXX | grep / >/dev/null) returns 0 if there is no directories
  • -print0 && -0 is to make xargs handle spaces in directory names
answered Apr 28 '11 at 15:05
Piotr Czapla
13.4k1976101

Here is solution which works on Linux and OS X:

find . -type d -execdir bash -c '[ "$(find {} -mindepth 1 -type d)" ] || echo $PWD/{}' \; 

or:

find . -type d -execdir sh -c 'test -z "$(find "{}" -mindepth 1 -type d)" && echo $PWD/{}' \;
answered Sep 23 '15 at 13:47
kenorb
56.9k25354350

What about this one ? It's portable and it doesn't depend on finnicky linking counts. Note however that it's important to put root/folder without the trailing /.

find root/folder -type d | awk '{ if (length($0)<length(prev) || substr($0,1,length(prev))!=prev) print prev; prev=($0 "/") } END { print prev }'
answered Sep 4 '15 at 3:06
DREV
11

Your Answer

 
community wiki

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

asked

7 years, 8 months ago

viewed

11,843 times

active

2 months ago

Love this site?

Get the weekly newsletter! In it, you'll get:

  • The week's top questions and answers
  • Important community announcements
  • Questions that need answers

see an example newsletter

Hot Network Questions