Was wird rekursiv auf alle Dateien im aktuellen Verzeichnis erweitert?

91

Ich weiß **/*.ext, dass alle Dateien in allen übereinstimmenden Unterverzeichnissen erweitert werden. *.extWas ist jedoch eine ähnliche Erweiterung, die alle diese Dateien auch im aktuellen Verzeichnis enthält?

Ramon
quelle
4
Mein Bash geht nicht damit um **/*.ext. Sind Sie sicher, dass es bei Ihnen funktioniert?
Tangens
@tangens Sie müssen die globstarOption gemäß Dennis Antwort aktivieren .
Kenorb

Antworten:

110

Dies funktioniert in Bash 4:

ls -l {,**/}*.ext

Damit der Doppelstern-Glob funktioniert, muss die globstarOption festgelegt werden (Standard: Ein):

shopt -s globstar

Von man bash:

    Globstar
                  Wenn festgelegt, wird das in einer Dateinamenerweiterung verwendete Muster ** verwendet
                  Text stimmt mit Dateien und null oder mehr Verzeichnissen überein und
                  Unterverzeichnisse. Wenn dem Muster nur ein / folgt, nur
                  Verzeichnisse und Unterverzeichnisse stimmen überein.

Jetzt frage ich mich, ob es vielleicht einmal einen Fehler in der Globstar-Verarbeitung gegeben hat, denn jetzt erhalte ls **/*.extich einfach die richtigen Ergebnisse.

Unabhängig davon habe ich mir die Analyse angesehen, die Kenorb mit dem VLC-Repository durchgeführt hat, und einige Probleme mit dieser Analyse und in meiner Antwort unmittelbar oben festgestellt:

Die Vergleiche mit der Ausgabe des findBefehls sind ungültig, da die Angabe -type fkeine anderen Dateitypen (insbesondere Verzeichnisse) enthält und die lsaufgeführten Befehle dies wahrscheinlich tun. Außerdem gibt einer der aufgelisteten Befehle ls -1 {,**/}*.*- der anscheinend auf meinem oben genannten basiert - nur Namen aus , die einen Punkt für die Dateien enthalten, die sich in Unterverzeichnissen befinden. Die Frage des OP und meine Antwort enthalten einen Punkt, da nach Dateien mit einer bestimmten Erweiterung gesucht wird.

Am wichtigsten ist jedoch, dass es ein spezielles Problem bei der Verwendung des lsBefehls mit dem Globstar-Muster gibt **. Viele Duplikate entstehen, da das Muster von Bash auf alle Dateinamen (und Verzeichnisnamen) im untersuchten Baum erweitert wird. Nach der Erweiterung lslistet der Befehl jeden von ihnen und ihren Inhalt auf, wenn es sich um Verzeichnisse handelt.

Beispiel:

In unserem aktuellen Verzeichnis befindet sich das Unterverzeichnis Aund sein Inhalt:

A
└── AB
    └── ABC
        ├── ABC1
        ├── ABC2
        └── ABCD
            └── ABCD1

**Erweitert in diesem Baum zu "AA / AB A / AB / ABC A / AB / ABC / ABC1 A / AB / ABC / ABC2 A / AB / ABC / ABCD A / AB / ABC / ABCD / ABCD1" (7 Einträge) . Wenn Sie dies tun echo **, erhalten Sie genau die Ausgabe, die Sie erhalten, und jeder Eintrag wird einmal dargestellt. Allerdings , wenn Sie das tun , ls **es wird eine Liste der zur Ausgabe jeder dieser Einträge. Im Wesentlichen ls Afolgt also ls A/ABusw., wird also A/ABzweimal angezeigt. Außerdem lswird die Ausgabe jedes Unterverzeichnisses voneinander unterschieden:

...
<blank line>
directory name:
content-item
content-item

Wenn Sie also zählen, werden wc -lalle Leerzeilen und Abschnittsüberschriften der Verzeichnisnamen verwendet, wodurch die Zählung noch weiter verschoben wird.

Dies ist ein weiterer Grund, warum Sie nicht analysieren solltenls .

Als Ergebnis dieser weiteren Analyse empfehle ich, das Globstar-Muster unter keinen anderen Umständen zu verwenden, als auf folgende Weise über einen Dateibaum zu iterieren:

for entry in **
do
    something "$entry"
done

Als letzten Vergleich habe ich ein Bash-Quell-Repository verwendet, das ich zur Hand hatte, und dies getan:

shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .

Ich habe trLeerzeichen in Zeilenumbrüche geändert, was hier nur gültig ist, da keine Namen Leerzeichen enthalten. Ich habe seddie führenden ./Zeilen aus jeder Ausgabezeile entfernt find. Ich habe die Ausgabe von sortiert, findda sie normalerweise unsortiert ist und Bashs Erweiterung der Globs bereits sortiert ist. Wie Sie sehen können, war die einzige Ausgabe von diffdie aktuelle Verzeichnisausgabe .von find. Als ich das tat, hatte ls ** | wc -ldie Ausgabe fast doppelt so viele Zeilen.

Bis auf weiteres angehalten.
quelle
5
Ich habe Ubuntu und Cygwin getestet und globstarist standardmäßigoff
Steven Penny
12
Die beste Antwort! aber ich denke **/*.extsollte aber genug sein. Außerdem haben Sie die versteckten Dateien nur, wenn Sie shopt -s dotglob.
gniourf_gniourf
2
So deaktivieren Sie globstar: shopt -u globstar.
Kenorb
4
@gniourf_gniourf Die Frage fragt tatsächlich, das aktuelle Verzeichnis speziell aufzunehmen, also nein, **/*.extwird nicht ausreichen
msciwoj
2
@dotnetCarpenter: Die mit MacOS gelieferte Version von Bash ist 3.2, die Globstar nicht unterstützt, wie Sie herausgefunden haben. Ein doppeltes Sternchen wird genauso behandelt wie ein einzelnes. Globstar wurde in Bash 4.0 eingeführt.
Bis auf weiteres angehalten.
13

Dadurch werden alle Dateien im aktuellen Verzeichnis und seinen Unterverzeichnissen gedruckt, die mit '.ext' enden.

find . -name '*.ext' -print
unutbu
quelle
Diese Antwort entspricht zwar nicht im engeren Sinne der vom OP geforderten "Erweiterung", führt jedoch höchstwahrscheinlich zum gewünschten Ergebnis.
Bis auf weiteres angehalten.
7

Sie können: verwenden **/*.*, um alle Dateien rekursiv einzuschließen (aktivieren durch :) shopt -s globstar.

Nachfolgend finden Sie Tests zu anderen Variationen und deren Verhalten.


Testordner mit 3472 Dateien im Beispiel- VLC- Repository-Ordner:

(Alle Dateien von 3472 gezählt als pro: find . -type f | wc -l)

  • ls -1 **/*.* - gibt 3338 zurück
  • ls -1 {,**/}*.*- gibt 3341 zurück (wie von Dennis vorgeschlagen )
  • ls -1 {,**/}* - gibt 8265 zurück
  • ls -1 **/*- gibt 7817 zurück, außer versteckte Dateien (wie von Dennis vorgeschlagen )
  • ls -1 **/{.[^.],}*- gibt 7869 zurück (wie von Dennis vorgeschlagen )
  • ls -1 {,**/}.?* - gibt 15855 zurück
  • ls -1 {,**/}.* - gibt 20321 zurück

Daher denke ich, dass die naheliegendste Methode zum rekursiven Auflisten aller Dateien das erste Beispiel ( **/*.*) gemäß gniourf-gniourf-Kommentar ist (vorausgesetzt, die Dateien haben die richtigen Erweiterungen oder verwenden die spezifische), da das zweite Beispiel einige weitere Duplikate wie unten enthält ::

$ diff -u <(ls -1 {,**/}*.*) <(ls -1 **/*.*)
--- /dev/fd/63  2015-04-19 15:25:07.000000000 +0100
+++ /dev/fd/62  2015-04-19 15:25:07.000000000 +0100
@@ -1,6 +1,4 @@
 COPYING.LIB
-COPYING.LIB
-Makefile.am
 Makefile.am
@@ -45,7 +43,6 @@
 compat/tdestroy.c
 compat/vasprintf.c
 configure.ac
-configure.ac

und die anderen erzeugen noch weitere Duplikate.


Verwenden Sie: shopt -s dotglob(deaktivieren durch shopt -u dotglob), um versteckte Dateien einzuschließen . Es wird nicht empfohlen, da es Befehle wie mvoder beeinflussen kann rmund Sie versehentlich die falschen Dateien entfernen können.

Kenorb
quelle
Auf Mac-Terminal und Bash mit aktiviertem Globstar fand ich die obige Lösung ( **/*.*) informativ und funktionierte am besten. Die akzeptierte Antwort verursachte Duplikate von Elementen im obersten Verzeichnis. Mein Arbeitsmuster war:"${path}"**/*.*
Mummybot
Es wäre interessant, dies mit anderen Optionen wie nullglob und dotglob zu versuchen
Wilf
3
$ find . -type f

Dadurch werden alle Dateien im aktuellen Verzeichnis aufgelistet. Sie können dann mit -exec einen anderen Befehl für die Ausgabe ausführen

$find . -type f -exec grep "foo" {} \;

Dadurch wird jede Datei aus der Suche nach der Zeichenfolge "foo" durchsucht.

Amir Afghani
quelle
Jetzt, da es 11 Jahre später ist, könnte es Zeit sein, dass jemand darauf hinweist, dass dies find . -type frekursiv mit dem Stammverzeichnis im aktuellen Verzeichnis gilt, nicht nur für das aktuelle Verzeichnis.
Roger Dahl
3

Warum nicht einfach die Klammererweiterung verwenden, um auch das aktuelle Verzeichnis einzuschließen?

./{*,**/*}.ext

Die Klammererweiterung erfolgt vor der Glob-Erweiterung, sodass Sie mit älteren Bash-Versionen effektiv das tun können, was Sie möchten, und in neueren Versionen auf das Monkeying mit Globstar verzichten können.

Es wird auch als gute Praxis in Bash angesehen, die führenden ./in Ihre Glob-Muster aufzunehmen.

clone206
quelle