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?
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:
Wenn Sie also zählen, werden wc -lalle Leerzeilen und Abschnittsüberschriften der Verzeichnisnamen verwendet, wodurch die Zählung noch weiter verschoben wird.
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:
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.
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.
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 ::
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.
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.
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.
**/*.ext
. Sind Sie sicher, dass es bei Ihnen funktioniert?globstar
Option gemäß Dennis Antwort aktivieren .Antworten:
Dies funktioniert in Bash 4:
Damit der Doppelstern-Glob funktioniert, muss die
globstar
Option festgelegt werden (Standard: Ein):Von
man bash
:Jetzt frage ich mich, ob es vielleicht einmal einen Fehler in der Globstar-Verarbeitung gegeben hat, denn jetzt erhalte
ls **/*.ext
ich 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
find
Befehls sind ungültig, da die Angabe-type f
keine anderen Dateitypen (insbesondere Verzeichnisse) enthält und diels
aufgeführten Befehle dies wahrscheinlich tun. Außerdem gibt einer der aufgelisteten Befehlels -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
ls
Befehls 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 Erweiterungls
listet der Befehl jeden von ihnen und ihren Inhalt auf, wenn es sich um Verzeichnisse handelt.Beispiel:
In unserem aktuellen Verzeichnis befindet sich das Unterverzeichnis
A
und sein Inhalt:**
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 tunecho **
, 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 Wesentlichenls A
folgt alsols A/AB
usw., wird alsoA/AB
zweimal angezeigt. Außerdemls
wird die Ausgabe jedes Unterverzeichnisses voneinander unterschieden:Wenn Sie also zählen, werden
wc -l
alle Leerzeilen und Abschnittsüberschriften der Verzeichnisnamen verwendet, wodurch die Zählung noch weiter verschoben wird.Dies ist ein weiterer Grund, warum Sie nicht analysieren sollten
ls
.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:
Als letzten Vergleich habe ich ein Bash-Quell-Repository verwendet, das ich zur Hand hatte, und dies getan:
Ich habe
tr
Leerzeichen in Zeilenumbrüche geändert, was hier nur gültig ist, da keine Namen Leerzeichen enthalten. Ich habesed
die führenden./
Zeilen aus jeder Ausgabezeile entferntfind
. Ich habe die Ausgabe von sortiert,find
da sie normalerweise unsortiert ist und Bashs Erweiterung der Globs bereits sortiert ist. Wie Sie sehen können, war die einzige Ausgabe vondiff
die aktuelle Verzeichnisausgabe.
vonfind
. Als ich das tat, hattels ** | wc -l
die Ausgabe fast doppelt so viele Zeilen.quelle
globstar
ist standardmäßigoff
**/*.ext
sollte aber genug sein. Außerdem haben Sie die versteckten Dateien nur, wenn Sieshopt -s dotglob
.globstar
:shopt -u globstar
.**/*.ext
wird nicht ausreichenDadurch werden alle Dateien im aktuellen Verzeichnis und seinen Unterverzeichnissen gedruckt, die mit '.ext' enden.
quelle
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ückls -1 {,**/}*.*
- gibt 3341 zurück (wie von Dennis vorgeschlagen )ls -1 {,**/}*
- gibt 8265 zurückls -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ückls -1 {,**/}.*
- gibt 20321 zurückDaher 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 ::und die anderen erzeugen noch weitere Duplikate.
Verwenden Sie:
shopt -s dotglob
(deaktivieren durchshopt -u dotglob
), um versteckte Dateien einzuschließen . Es wird nicht empfohlen, da es Befehle wiemv
oder beeinflussen kannrm
und Sie versehentlich die falschen Dateien entfernen können.quelle
**/*.*
) informativ und funktionierte am besten. Die akzeptierte Antwort verursachte Duplikate von Elementen im obersten Verzeichnis. Mein Arbeitsmuster war:"${path}"**/*.*
Dadurch werden alle Dateien im aktuellen Verzeichnis aufgelistet. Sie können dann mit -exec einen anderen Befehl für die Ausgabe ausführen
Dadurch wird jede Datei aus der Suche nach der Zeichenfolge "foo" durchsucht.
quelle
find . -type f
rekursiv mit dem Stammverzeichnis im aktuellen Verzeichnis gilt, nicht nur für das aktuelle Verzeichnis.Warum nicht einfach die Klammererweiterung verwenden, um auch das aktuelle Verzeichnis einzuschließen?
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.quelle