Ich hatte immer wieder dieses Problem: Ich habe einen Glob, der genau den richtigen Dateien entspricht, aber Ursachen hat Command line too long
. Jedes Mal , wenn ich es auf eine Kombination von umgestellt habe find
und grep
dass die Arbeiten für die besondere Situation, die aber nicht 100% entspricht.
Beispielsweise:
./foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg
Gibt es ein Tool zum Konvertieren von Globs in find
Ausdrücke, die mir nicht bekannt sind? Oder gibt es eine Option find
zum Abgleichen des Globs, ohne dass derselbe Glob in einem Unterverzeichnis übereinstimmt (z. B. foo/*.jpg
darf er nicht übereinstimmen bar/foo/*.jpg
)?
-path
oder zu verwenden-ipath
.find . -path './foo*bar/quux[A-Z]/pic[0-9][0-9][0-9][0-9]?.jpg'
sollte funktionieren - außer dass es passt/fooz/blah/bar/quuxA/pic1234d.jpg
. Wird das ein Problem sein?echo <glob> | cat
, vorausgesetzt mein Wissen über Bash, Echo istAntworten:
Wenn das Problem darin besteht, dass Sie einen Fehler erhalten, bei dem die Argumentliste zu lang ist, verwenden Sie eine Schleife oder eine integrierte Shell. Während
command glob-that-matches-too-much
Fehler auftreten können,for f in glob-that-matches-too-much
nicht, so können Sie einfach tun:Die Schleife mag unerträglich langsam sein, aber sie sollte funktionieren.
Oder:
(
printf
Da dies in den meisten Shells integriert ist, umgeht das oben Gesagte die Einschränkung desexecve()
Systemaufrufs.)Funktioniert auch mit Bash. Ich bin mir jedoch nicht sicher, wo genau dies dokumentiert ist.
Sowohl Vims
glob2regpat()
als auch Pythonsfnmatch.translate()
können Globs in reguläre Ausdrücke konvertieren, aber beide verwenden sie auch.*
für*
Übereinstimmungen zwischen/
.quelle
something
mitecho
sollte es tun.printf
- es ist schneller alsecho
tausende Male anzurufen und bietet mehr Flexibilität.exec
, was für externe Befehle gilt, wie zcat
. Diese Begrenzung gilt jedoch nicht für Shell-integrierte Befehle wieprintf
.printf
ist, und die Shells verwenden vermutlich dieselbe Methode zum Bereitstellen von Argumenten, die sie zum Auflisten von Argumenten verwendenfor
.cat
ist kein eingebauter.mksh
woprintf
nicht eingebaut ist und Muscheln wieksh93
wo gebautcat
ist (oder sein kann). Siehe auchzargs
inzsh
, um es zu umgehen, ohne darauf zurückgreifen zu müssenxargs
.find
(für die Prädikate-name
/-path
standard) verwendet Platzhaltermuster wie Globs (beachten Sie, dass dies{a,b}
kein Glob-Operator ist; nach der Erweiterung erhalten Sie zwei Globs). Der Hauptunterschied ist die Behandlung von Schrägstrichen (und Punktdateien und Verzeichnissen, die nicht speziell behandelt werdenfind
).*
in Globs werden nicht mehrere Verzeichnisse überspannt.*/*/*
Dadurch werden bis zu 2 Verzeichnisebenen aufgelistet. Das Hinzufügen von a entspricht-path './*/*/*'
allen Dateien, die mindestens 3 Ebenen tief sind, und hört nicht auf,find
den Inhalt eines Verzeichnisses in irgendeiner Tiefe aufzulisten.Für diesen besonderen
Ein paar Globs, es ist einfach zu übersetzen. Sie möchten Verzeichnisse in Tiefe 3, damit Sie Folgendes verwenden können:
(oder
-depth 3
mit einigenfind
Implementierungen). Oder POSIXly:Welches würde garantieren, dass diese
*
und?
nicht/
Zeichen übereinstimmen konnten .(Im
find
Gegensatz zu Globs würde der Inhalt anderer Verzeichnisse alsfoo*bar
der im aktuellen Verzeichnis¹ gelesen und die Liste der Dateien nicht sortiert. Wenn wir jedoch das Problem außer Acht lassen, dass das, was übereinstimmt,[A-Z]
oder das Verhalten von*
/?
in Bezug auf ungültige Zeichen ist nicht spezifiziert, würden Sie die gleiche Liste von Dateien erhalten).Wie @muru gezeigt hat , muss auf keinen Fall darauf zurückgegriffen werden,
find
wenn nur die Liste der Dateien in mehrere Läufe aufgeteilt werden soll, um das Limit desexecve()
Systemaufrufs zu umgehen. Einige Shells wiezsh
(mitzargs
) oderksh93
(mitcommand -x
) haben sogar eine eingebaute Unterstützung dafür.Mit
zsh
(deren Globs auch das Äquivalent-type f
und die meisten anderenfind
Prädikate haben), zum Beispiel:(
(|.bak)
Ist ein glob Betreiber entgegen{,.bak}
, das(.)
glob Qualifier die äquivalent istfind
‚s-type f
, fügen SieoN
dort mit der Sortierung wie zu überspringenfind
,D
schließen Punkt-Dateien (gilt nicht für diesen glob))¹ Um
find
den Verzeichnisbaum wie Globs zu crawlen, benötigen Sie Folgendes:Das heißt beschneiden alle Verzeichnisse auf Stufe 1 bis auf die
foo*bar
eine, und alle auf Stufe 2 , mit Ausnahme derquux[A-Z]
oderquux[A-Z].bak
Einsen, und wählen Sie diepic...
diejenigen auf der Ebene 3 (und beschneiden alle Verzeichnisse auf dieser Ebene).quelle
Sie können eine Regex schreiben, um eine Suche zu finden, die Ihren Anforderungen entspricht:
quelle
.
, das Hinzufügen der optionalen Übereinstimmung für.bak
und die Änderung*
von[^/]*
, um Pfaden wie / foo / foo / bar usw. nicht zu entsprechen.[0-9][0-9][0-9][0-9]?
auf[0-9]{3,4}
Wenn Sie den Hinweis zu meiner anderen Antwort als direktere Antwort auf Ihre Frage verallgemeinern , können Sie dieses POSIX-
sh
Skript verwenden, um den Glob in einenfind
Ausdruck zu konvertieren :Um mit verwendet werden , ein Standard -
sh
glob (also nicht die beiden Klackse Ihres Beispiel , das verwendet Klammer Erweiterung ):(das ignoriert keine Punktdateien oder Punktverzeichnisse außer
.
und..
sortiert die Liste der Dateien nicht).Dieser funktioniert nur mit Globs relativ zum aktuellen Verzeichnis, ohne
.
oder mit..
Komponenten. Mit etwas Aufwand können Sie es auf jeden Globus erweitern, mehr als auf einen Globus ... Das könnte auch so optimiert werden, dassglob2find 'dir/*'
es nicht so aussiehtdir
wie bei einem Muster.quelle