Użyj GNU find, aby wyświetlić tylko katalogi liści

Próbuję użyć GNU find, aby znaleźć tylko katalogi, które nie zawierają innych katalogów, ale mogą lub nie mogą zawierać zwykłych plików.

Moje najlepsze przypuszczenie do tej pory było:

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

Ale to daje mi długą listę "."

Dzięki!
Author: Thomas G Henry, 2010-11-24

6 answers

Możesz użyć -links, jeśli Twój system plików jest zgodny ze standardem POSIX (tzn. katalog ma łącze dla każdego podkatalogu w nim, łącze od jego rodzica i łącze do self, a więc łącze z liczbą 2, jeśli nie ma podkatalogów).

Następujące polecenie powinno zrobić to, co chcesz:

find dir -type d -links 2

Wydaje się jednak, że nie działa na Mac OS X (jak wspomniał @Piotr). Oto kolejna wersja, która jest wolniejsza, ale działa na Mac OS X. jest oparta na jego wersji, z korekcją obsługi białych znaków w nazwy katalogów:

find . -type d -exec sh -c '(ls -p "{}"|grep />/dev/null)||echo "{}"' \;
 65
Author: Sylvain Defresne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-30 20:30:39

Właśnie znalazłem inne rozwiązanie, które działa zarówno na Linuksie , jak i macOS (Bez find -exec)!

Obejmuje sort (dwa razy) i awk:

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

Wyjaśnienie:

  1. Sortuj wyjście find w odwrotnej kolejności

    • teraz najpierw pojawiają się podkatalogi, potem ich rodzice
  2. Użyj awk, aby pominąć linie, jeśli bieżąca linia jest prefiksem poprzedniej linii

    • (to polecenie pochodzi z odpowiedz tutaj )
    • teraz wyeliminowałeś " wszystkie katalogi rodzica "(zostajesz z parent dirs)
  3. sort them (więc wygląda jak normalne wyjście find)
  4. Voila! Szybki i przenośny.
 5
Author: Ahmet Alp Balkan - Google,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-27 03:59:20

@Sylvian rozwiązanie nie działa dla mnie na mac os x z jakiegoś niejasnego powodu. Więc wymyśliłem bardziej bezpośrednie rozwiązanie. Mam nadzieję, że to komuś pomoże:

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

Wyjaśnienie:

  • ls -p kończy katalogi znakiem ' / '
  • więc (ls -p XXX | grep / >/dev/null) zwraca 0 jeśli nie ma katalogów
  • -print0 && -0 Aby xargs obsługiwał spacje w nazwach katalogów
 1
Author: Piotr Czapla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-28 15:05:39

A co z tym ? Jest przenośny i nie zależy od liczby połączeń. Należy jednak pamiętać, że ważne jest, aby umieścić root/folder Bez końcówki/.

find root/folder -type d | awk '{ if (length($0)<length(prev) || substr($0,1,length(prev))!=prev) print prev; prev=($0 "/") } END { print prev }'
 0
Author: DREV,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-04 03:06:02

Oto rozwiązanie, które działa na Linuksie i OS X:

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

Lub:

find . -type d -execdir sh -c 'test -z "$(find "{}" -mindepth 1 -type d)" && echo $PWD/{}' \;
 0
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-23 14:09:51

W drzewach katalogów mam kilka dziwnie nazwanych plików, które mylą awk jak w @AhmetAlpBalkan odpowiedz Więc przyjęłam nieco inne podejście

  p=;
  while read c;
    do 
      l=${#c};
      f=${p:0:$l};
      if [ "$f" != "$c" ]; then 
        echo $c; 
      fi;
      p=$c; 
    done < <(find . -type d | sort -r) 

Tak jak w rozwiązaniu awk, odwracam sortowanie. W ten sposób, jeśli ścieżka katalogu jest ścieżką podrzędną poprzedniego trafienia, możesz łatwo to rozpoznać.

Tutaj p to mój poprzedni mecz, {[4] } to bieżący Mecz, {[5] } to długość bieżącego meczu, f to pierwsze l pasujące znaki poprzedniego meczu. I tylko echo te trafienia, które nie pasują do początku poprzedniego meczu.

Problem z rozwiązaniem awk polega na tym, że dopasowanie początku łańcucha znaków wydaje się być mylone, jeśli nazwa ścieżki zawiera w nazwach niektórych podkatalogów rzeczy takie jak +. To spowodowało, że awk zwróciło mi wiele fałszywych alarmów.

 0
Author: A.Ellett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-23 16:07:01