Gebruik GNU find om alleen de bladmappen weer te geven

Ik probeer GNU find te gebruiken om alleen de mappen te vinden die geen andere mappen bevatten, maar die al dan niet gewone bestanden bevatten.

Mijn beste gok tot nu toe is:

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

maar dit levert me een lange lijst op van “.”

Bedankt!


Antwoord 1, autoriteit 100%

U kunt -links gebruiken als uw bestandssysteem POSIX-compatibel is (dwz een directory heeft een link voor elke subdirectory erin, een link van zijn bovenliggende en een link naar zichzelf, dus een telling van 2 link als het geen subdirectories heeft ).

Het volgende commando zou moeten doen wat je wilt:

find dir -type d -links 2

Het lijkt echter niet te werken op Mac OS X (zoals @Piotr vermeldde). Hier is een andere versie die langzamer is, maar wel werkt op Mac OS X. Het is gebaseerd op zijn versie, met een correctie om witruimte in mapnamen te verwerken:

find . -type d -exec sh -c '(ls -p "{}"|grep />/dev/null)||echo "{}"' \;

Antwoord 2, autoriteit 7%

Ik heb zojuist een andere oplossing hiervoor gevonden die werkt op zowel Linux & macOS (zonder find -exec)!

Het gaat om sort(tweemaal) en awk:

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

Uitleg:

  1. sorteer de find-uitvoer in omgekeerde volgorde

    • nu heb je subdirectories die eerst verschijnen, dan hun ouders
  2. gebruik awkom regels weg te laten als de huidige regel een prefix is ​​van de vorige regel

    • (deze opdracht is van de antwoord hier)
    • nu heb je “alle bovenliggende mappen” geëlimineerd (je blijft achter met bovenliggende mappen)
  3. sortze (zodat het lijkt op de normale find-uitvoer)
  4. Voila! Snel en draagbaar.

Antwoord 3, autoriteit 2%

@Sylvian-oplossing werkte om een ​​of andere onduidelijke reden niet voor mij op mac os x. Dus ik heb een wat directere oplossing bedacht. Ik hoop dat dit iemand zal helpen:

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

Uitleg:

  • ls -peindigt mappen met ‘/’
  • dus (ls -p XXX | grep / >/dev/null)geeft 0 terug als er geen mappen zijn
  • -print0&& -0is om xargs spaties in directorynamen te laten verwerken

Antwoord 4, autoriteit 2%

Ik heb een paar vreemd benoemde bestanden in mijn directorystructuren die awkverwarren zoals in
@AhmetAlpBalkan’s antwoord. Dus nam ik een iets andere benadering

 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) 

Net als in de awk-oplossing, sorteer ik omgekeerd. Op die manier kun je dit gemakkelijk onderscheiden als het directorypad een subpad is van de vorige hit.

Hier is pmijn vorige match, cis de huidige match, lis de lengte van de huidige match, fis de eerste lovereenkomende karakters van de vorige match. Ik echoalleen die hits die niet overeenkomen met het begin van de vorige wedstrijd.

Het probleem met de aangeboden awk-oplossing is dat het matchen van het begin van de tekenreeks verward lijkt te zijn als de padnaam dingen bevat zoals +in de naam van enkele van de subdirectories. Dit zorgde ervoor dat awkeen aantal valse positieven voor mij retourneerde.


Antwoord 5

Deze awk/sort-pipe werkt een beetje beter dan de oorspronkelijk voorgestelde in dit antwoord, maar is er sterk op gebaseerd 🙂 Het zal betrouwbaarder werken, ongeacht of het pad speciale regex-tekens bevat of niet:

find . -type d | sort -r | awk 'index(a,$0)!=1{a=$0;print}' | sort

Onthoud dat awkstrings 1-geïndexeerd zijn in plaats van 0-geïndexeerd, wat vreemd kan zijn als je gewend bent om met op C gebaseerde talen te werken.

Als de index van de huidige regel in de vorige regel 1 is (dwz hij begint ermee), dan slaan we deze over, wat net zo werkt als de match van "^"$0.


Antwoord 6

En deze? Het is draagbaar en het is niet afhankelijk van finnicky koppelingen. Merk echter op dat het belangrijk is om root/folderzonderde achterliggende / te plaatsen.

find root/folder -type d | awk '{ if (length($0)<length(prev) || substr($0,1,length(prev))!=prev) print prev; prev=($0 "/") } END { print prev }'

Antwoord 7

Hier is een oplossing die werkt op Linux en OS X:

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

of:

find . -type d -execdir sh -c 'test -z "$(find "{}" -mindepth 1 -type d)" && echo $PWD/{}' \;

Other episodes