Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find all directories, that don't contain other directories

Tags:

find

bash

Currently:

$ find -type d
./a
./a/sub
./b
./b/sub
./b/sub/dub
./c/sub
./c/bub

I need:

$ find -type d -not -contains -type d
./a/sub
./b/sub/dub
./c/sub
./c/bub

How do I exclude directories, that contain other (sub)directories, but are not empty (contain files)?

like image 709
u15p7fgy863eiq5 Avatar asked Mar 02 '23 03:03

u15p7fgy863eiq5


1 Answers

You can find the leaf directories that only have 2 links (or less) and then check if each found directory contains some files.

Something like this:

# find leaf directories
find -type d -links -3 -print0 | while read -d '' dir
do
    # check if it contains some files
    if ls -1qA "$dir" | grep -q .
    then
        echo "$dir"
    fi
done

Or simply:

find -type d -links -3 ! -empty

Note that you may need the find option -noleaf on some filesystems, like CD-ROM or some MS-DOS filesystems. It works without it in WSL2 though.

In the btrfs filesystem the directories always have 1 link so using -links won't work there.

A much slower, but filesystem agnostic, find based version:

prev='///' # some impossible dir

# A depth first find to collect non-empty directories
readarray -d '' dirs < <(find -depth -type d ! -empty -print0)

for dir in "${dirs[@]}"
do
    dirterm=$dir'/'

    # skip if it matches the previous dir
    [[ $dirterm == ${prev:0:${#dirterm}} ]] && continue

    # skip if it has sub directories
    [[ $(find "$dir" -mindepth 1 -maxdepth 1 -type d -print -quit) != '' ]] && continue

    echo "$dir"
    prev=$dir
done # add "| sort" if you want the same order as a "find" without "-depth"
like image 153
Ted Lyngmo Avatar answered Mar 11 '23 21:03

Ted Lyngmo