`find -name` Muster, das mehreren Mustern entspricht

334

Ich habe versucht, mit dem Befehl eine Liste aller Python- und HTML-Dateien in einem Verzeichnis abzurufen find Documents -name "*.{py,html}".

Dann kam die Manpage:

Klammern innerhalb des Musters ('{}') gelten nicht als speziell (dh find. -Name 'foo {1,2}' entspricht einer Datei mit dem Namen foo {1,2}, nicht den Dateien foo1 und foo2.

Da dies Teil einer Pipe-Kette ist, möchte ich angeben können, mit welchen Erweiterungen sie zur Laufzeit übereinstimmt (keine Hardcodierung). Wenn find es einfach nicht kann, wäre ein Perl-Einzeiler (oder ähnliches) in Ordnung.

Bearbeiten: Die Antwort, die ich schließlich gefunden habe, enthält alle Arten von Mist und ist auch ein bisschen lang, also habe ich sie als Antwort auf den ursprünglichen Juckreiz gepostet , den ich zu kratzen versuchte. Fühlen Sie sich frei, das zu hacken, wenn Sie bessere Lösungen haben.

Xiong Chiamiov
quelle
Ein häufig übersehenes und nicht ausreichend genutztes Dienstprogramm ist auch locate, wenn auch mit der Einschränkung, dass das interne Updateb möglicherweise nicht auf dem neuesten Stand ist. Aber es ist schnell.
Michael
Ich
stimme dafür,

Antworten:

480

Verwenden Sie -o, was "oder" bedeutet:

find Documents \( -name "*.py" -o -name "*.html" \)

Sie müssten diese Befehlszeile programmgesteuert erstellen, was nicht so einfach ist.

Verwenden Sie Bash (oder Cygwin unter Windows)? Wenn ja, sollten Sie in der Lage sein:

ls **/*.py **/*.html

Das könnte einfacher programmgesteuert sein.

RichieHindle
quelle
3
Ich verwende zsh, das in der Regel alle Bashismen und mehr unterstützt.
Xiong Chiamiov
12
Zsh unterstützt die **rekursive Suche; Bash unterstützt es nur in Versionen 4.0 und höher und nur mit shopt -s globstar.
Ephemient
2
Wie viele Argumente können Sie haben? Ich habe eine möglicherweise große Liste von .gcda-Dateien (Coverage Data) zum Aufbau
Jasper Blues
40
Sie müssen die beiden -names mit Klammern umgeben, wenn Sie verwenden -exec. ZBfind Documents \( -name "*.py" -o -name "*.html" \) -exec file {} \;
Artbristol
2
Der Kommentar zu @artbristol ist sehr relevant, wenn Sie beispielsweise ein hinzufügen -print0, um Dateinamen mit Leerzeichen zu behandeln.
Nimrodm
63

Einige Editionen von find, hauptsächlich auf Linux-Systemen, möglicherweise auch auf anderen, unterstützen die Optionen -regex und -regextype, wodurch Dateien mit Namen gefunden werden, die mit dem regulären Ausdruck übereinstimmen.

zum Beispiel

find . -regextype posix-egrep -regex ".*\.(py|html)$" 

sollte den Trick im obigen Beispiel tun. Dies ist jedoch keine Standard-POSIX-Suchfunktion und ist implementierungsabhängig.

intelekt
quelle
1
Interessant,
12
Einfacher: find . -regex ".*\.\(py\|html\)$"Dies funktioniert, da standardmäßig reguläre Ausdrücke im Emacs-Stil gefunden werden, die sich geringfügig unterscheiden, sodass Sie den regulären Texttyp nicht angeben müssen.
Robru
2
Wenn Sie viele Ausdrücke haben, -regextype posix-egrepist dies praktisch (andernfalls müssen Sie viele Zeichen maskieren). Dies ist der Befehl find, den ich für einen Dist-Hook verwendet habe, der eine Windows-Distributions-Zip-Datei erstellt (findet die zu ändernden Dateien und ändert sie in der Datei in dos-eol):find -regextype posix-egrep -regex ".*(\.([chyl]|def|cpy|cob|conf|cfg)|(README|ChangeLog|AUTHORS|ABOUT-NLS|NEWS|THANKS|TODO|COPYING.*))$" -exec sed -i -e 's/\r*$/\r/' {} \;
Simon Sobisch
32

Sie können programmgesteuert weitere -nameKlauseln hinzufügen , die durch Folgendes getrennt sind -or:

find Documents \( -name "*.py" -or -name "*.html" \)

Oder wählen Sie stattdessen eine einfache Schleife:

for F in Documents/*.{py,html}; do ...something with each '$F'... ; done
Stephan202
quelle
@ user2284570: dann gibt es entweder keine *.pyDateien oder Sie haben eine ungerade Version von find. Der oben aufgeführte Befehl funktioniert einwandfrei.
Stephan202
Nein, ich benutze -iname. Es zurückkehren *.pyDateien nur , wenn Schreib es in der letzten Position (so iname *.htmlder erste Ausdruck ist) . Ich benutze den Befehl auf Debian.
user2284570
Verwenden Sie Anführungszeichen? Das ist sehr wichtig.
Stephan202
1
Ist es ein -oder oder ein -o?
Stephane
1
@StephaneEybert: Beides ist in Ordnung, aber nur letzteres ist POSIX-konform (laut Manpage).
Stephan202
16

Dadurch werden alle .c- oder .cpp-Dateien unter Linux gefunden

$ find . -name "*.c" -o -name "*.cpp"

Du brauchst die maskierte Klammer nicht, es sei denn, du machst einige zusätzliche Mods. Hier von der Manpage sagen sie, wenn das Muster übereinstimmt, drucken Sie es aus. Vielleicht versuchen sie, das Drucken zu kontrollieren. In diesem Fall fungiert der -print als Bedingung und wird zu einer "AND'd" -Bedingung. Dadurch wird verhindert, dass C-Dateien gedruckt werden.

$ find .  -name "*.c" -o -name "*.cpp"  -print

Wenn Ihnen die ursprüngliche Antwort gefällt, können Sie den Druck steuern. Dadurch werden auch alle .c-Dateien gefunden.

$ find . \( -name "*.c" -o -name "*.cpp" \) -print

Ein letztes Beispiel für alle c / c ++ - Quelldateien

$ find . \( -name "*.c" -o -name "*.cpp"  -o -name "*.h" -o -name "*.hpp" \) -print
Netskink
quelle
11

Ich hatte ein ähnliches Bedürfnis. Das hat bei mir funktioniert:

find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print
bkidd
quelle
3
Perfekt. Aber ich finde es ein bisschen seltsam, dass es ohne die()
pedrofurla
Ich wollte Dateien finden, die mit * .c * .cpp oder * .cc übereinstimmen. Mit nur zwei Namensmustern brauchte ich keine Parens, aber mit drei Namensmustern, die mit zwei -o-Mustern verbunden waren, musste find -name "*.cpp" -o -name "*.c" -o -name "*.cc" -print0ich ein Paar Parens verwenden Gruppieren Sie den zweiten oder Operator. find -name "*.cpp" -o \( -name "*.c" -o -name "*.cc" \) -print0Es kann sein, dass der -print0, der immer "true" ist, die Logik beeinflusst hat.
Cardiff Space Man
5

Mein Standard war:

find -type f | egrep -i "*.java|*.css|*.cs|*.sql"

Wie die weniger prozessintensive findAusführung von Brendan Long und Stephan202 et al.:

find Documents \( -name "*.py" -or -name "*.html" \)

PaSe
quelle
3
Das ist keine korrekte Verwendung von egrepregulärem Ausdruck, sondern Sie haben einen Shell-Glob, in dem ein regulärer Ausdruck verwendet werden sollte. (Typische findVerwendung ist auch : find {directory} [options...] [action], wo, abhängig von impl, directorystandardmäßig .und actionstandardmäßig verwendet wird -print, aber ich werde explizit sein.) Verwenden Sie stattdessen etwas wie: find . -type f -print | egrep -i '\.java$|\.css$|\.cs$|\.sql$' Aber auch, als wirklich schnelle Alternative zu find, könnte man auch versuchen Sie es locateauf ähnliche Weise (wenn auch nicht unbedingt aktuell, da eine interne Datenbank nach einer Dateiliste
abgefragt wird
2
#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done

einfach aber funktioniert :)

mnrl
quelle
1

Ich musste alle Dateien in untergeordneten Verzeichnissen mit Ausnahme einiger Dateien entfernen. Folgendes hat bei mir funktioniert (drei Muster angegeben):

find . -depth -type f -not -name *.itp -and -not -name *ane.gro -and -not -name *.top -exec rm '{}' +
Adobe
quelle
1

Klammern innerhalb des Musters \(\)sind für das Namensmuster mit erforderlichor

find Documents -type f \( -name "*.py" -or -name "*.html" \)

Während für das Namensmuster mit andOperator es nicht erforderlich ist

find Documents -type f ! -name "*.py" -and ! -name "*.html" 
Chetabahana
quelle
0

Dies funktioniert auf AIX Korn Shell.

find *.cbl *.dms -prune -type f -mtime -1

Dies sucht *.cbloder *.dmsist 1 Tag alt, nur im aktuellen Verzeichnis, wobei die Unterverzeichnisse übersprungen werden.

Abdul M Gill
quelle
0
find MyDir -iname "*.[j][p][g]"
+
find MyDir -iname "*.[b][m][p]"
=
find MyDir -iname "*.[jb][pm][gp]"
user7531934
quelle
2
Beachten Sie, dass letzteres mit foo.jmg übereinstimmt, aber keines der beiden besten.
Kupfer. Was
0

Wie wäre es mit

ls {*.py,*.html}

Es listet alle Dateien auf, die in ihren Dateinamen mit .py oder .html enden

Dr_Hope
quelle