Rekursiver Globus?

80

Ich würde gerne so etwas schreiben:

$ ls **.py

Um alle .py-Dateinamen abzurufen, durchlaufen Sie rekursiv eine Verzeichnishierarchie.

Auch wenn .py-Dateien zu finden sind, gibt die Shell (Bash) Folgendes aus:

ls: cannot access **.py: No such file or directory

Wie kann ich tun, was ich will?

EDIT: Ich möchte angeben, dass ich nicht an dem konkreten Fall von interessiert bin ls, aber die Frage ist über die Glob-Syntax.

Paolo
quelle

Antworten:

98

Um rekursive Globs in Bash auszuführen, benötigen Sie die globstarFunktion ab Bash-Version 4 oder höher.

Aus der Bash-Manpage:

globstar
    If set, the pattern ** used in a pathname expansion context will
    match all files and zero or more directories and subdirectories.
    If the pattern is followed by a /, only directories and
    subdirectories match.

Für Ihr Beispielmuster:

shopt -s globstar
ls **/*.py
Jordanien
quelle
2
Ich würde auch empfehlennullglob
Glenn Jackman
6
@glennjackman Aber bevor nullglobich es aktiviere , würde ich dringend empfehlen, folgende Warnungen zu lesen .
Serge Stroobandt
2
^ Warnungen sind hierher gezogen .
Usandfriends
1
Funktioniert mit Bash 3.2 wc -l {**,.}/*.pyeinwandfrei
Raphael
@Raphael Ich habe die Release Notes zweimal durchgesehen und es heißt definitiv, dass es in 4.0 eingeführt wurde. Vielleicht hat Ihre Distribution einen Patch dafür zurückportiert? IIRC RHEL 5 hatte einige Funktionen zurückportiert. Bemerkenswert ist auch, dass es 9 Jahre her ist, seit Bash 4 veröffentlicht wurde ...
Jordan
10
find . -name '*.py'

** macht nur einen einzigen *, beide arbeiten im aktuellen Verzeichnis

doneal24
quelle
Interessant. Ich konzentriere mich jedoch mehr auf die Glob-Syntax selbst, da ich sie in einer Konfigurationsdatei verwenden muss (Include-Direktive). Ich brauche keine Dateiliste.
Paolo
2
@Doug O'Neal, das stimmt nicht mehr. bash hat diese zsh-Funktion jetzt kopiert (obwohl sie eine Syntax verwendet hat, die der von ksh93 ähnelt und die zsh-Globbing-Qualifikationsmerkmale noch nicht unterstützt, was die Nützlichkeit einschränkt)
Stéphane Chazelas
Es gibt viele Dinge, die Sie tun können, findwenn Sie nicht Bash 4 haben. Beispiele: yourcommand `find . -name '*.py'`(Beachten Sie die Backticks); find . -name '*.py' -exec yourcommand {} \;.
Mars
5

Seit Bash 4 (einschließlich zsh) wurde eine neue Globbing-Option ( globstar) hinzugefügt, die das Muster **anders behandelt, wenn es gesetzt ist.

Es stimmt mit dem Platzhaltermuster überein und gibt die übereinstimmenden Datei- und Verzeichnisnamen zurück, indem das Platzhaltermuster im Befehl durch die übereinstimmenden Elemente ersetzt wird.

Normalerweise **funktioniert es bei der Verwendung ähnlich *, aber es rekursiv alle Verzeichnisse (wie eine Schleife).

Um festzustellen, ob es aktiviert ist, überprüfen Sie es mit shopt globstar(in Skripten verwenden Sie shopt -q globstar).

Das Beispiel **.pywürde nur für das aktuelle Verzeichnis funktionieren, da es keine Liste der Verzeichnisse zurückgibt, die rekursiv sein können. Aus diesem Grund müssen Sie Platzhalter auf mehreren Verzeichnisebenen verwenden **/*.py, damit es tiefer geht.

Bitte finden auf SO wenige Syntax Tests , die ich habe für rekursiv alle Dateien zu finden.

Kenorb
quelle