Wzorzec `find -name`, który pasuje do wielu wzorców

334

Próbowałem uzyskać listę wszystkich plików Pythona i HTML w katalogu z poleceniem find Documents -name "*.{py,html}".

Potem przyszła strona podręcznika:

Nawiasy klamrowe we wzorcu („{}”) nie są uważane za specjalne (tj. Znajdź. -Name 'foo {1,2}' pasuje do pliku o nazwie foo {1,2}, a nie do plików foo1 i foo2.

Ponieważ jest to część łańcucha potoków, chciałbym móc określić, które rozszerzenia pasują w czasie wykonywania (bez kodowania). Jeśli find po prostu nie może tego zrobić, perl-one-liner (lub podobny) byłby w porządku.

Edycja: Odpowiedź, którą w końcu wymyśliłem, obejmuje różnego rodzaju badziewie i jest również trochę długa, więc opublikowałem ją jako odpowiedź na pierwotny świąd, który próbowałem podrapać. Jeśli masz lepsze rozwiązania, możesz je zhakować.

Xiong Chiamiov
źródło
Często pomijanym i niedostatecznie wykorzystywanym narzędziem jest locatejednak, z zastrzeżeniem, że wewnętrzna aktualizacja może nie być aktualna. Ale to jest szybkie.
Michael
Głosuję za zamknięciem tego pytania jako nie na temat, ponieważ należy ono do systemów Unix i Linux
Dan Dascalescu,

Odpowiedzi:

480

Użyj -o, co oznacza „lub”:

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

Trzeba by zbudować ten wiersz poleceń programowo, co nie jest takie łatwe.

Czy używasz bash (lub Cygwin w systemie Windows)? Jeśli tak, powinieneś być w stanie to zrobić:

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

który może być łatwiejszy do zbudowania programowo.

RichieHindle
źródło
3
Korzystam z zsh, który z reguły obsługuje wszystkie bashizmy i więcej.
Xiong Chiamiov
12
Zsh obsługuje **wyszukiwanie rekurencyjne; Bash obsługuje go tylko w wersjach 4.0 i nowszych, i tylko z shopt -s globstar.
ephemient
2
Ile możesz mieć argumentów? Mam potencjalnie dużą listę plików .gcda (dane pokrycia) do zbudowania
Jasper Blues
40
Musisz -nameużyć dwóch nawiasów klamrowych, jeśli używasz -exec. Np.find Documents \( -name "*.py" -o -name "*.html" \) -exec file {} \;
artbristol
2
Komentarz @artbristol jest bardzo istotny, jeśli na przykład dodajesz -print0do obsługi nazw plików ze spacjami.
nimrodm
63

Niektóre edycje find, głównie w systemach Linux, prawdopodobnie w innych również obsługują opcje -regex i -regextype, które wyszukują pliki o nazwach pasujących do wyrażenia regularnego.

na przykład

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

powinien zrobić lewę w powyższym przykładzie. Nie jest to jednak standardowa funkcja wyszukiwania POSIX i zależy od implementacji.

intelekt
źródło
1
ciekawe, ale bardziej
skomplikowane
12
Prostsze: find . -regex ".*\.\(py\|html\)$"działa, ponieważ domyślnie znajdują się wyrażenia regularne w stylu Emacsa, które są nieco inne, więc nie trzeba określać typu wyrażenia regularnego.
robru 24.04.2013
2
Jeśli masz wiele wyrażeń, -regextype posix-egrepjest to przydatne (w przeciwnym razie musisz uciec od wielu znaków). Jest to polecenie find, którego użyłem do zakończenia dystrybucji budowania pliku ZIP dystrybucji systemu Windows (wyszukuje pliki do zmiany, a plik zmienia je w 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

Możesz programowo dodać więcej -nameklauzul, oddzielonych -or:

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

Lub przejdź do prostej pętli zamiast:

for F in Documents/*.{py,html}; do ...something with each '$F'... ; done
Stephan202
źródło
@ user2284570: wtedy albo nie ma *.pyplików, albo masz dziwną wersję find. Polecenie wymienione powyżej działa dobrze.
Stephan202,
Nie, używam -iname. Zwraca *.pypliki tylko wtedy, gdy zapisze je w ostatniej pozycji (podobnie iname *.htmljak pierwsze wyrażenie) . Używam polecenia w Debianie.
user2284570,
Czy używasz cytatów? To bardzo ważne.
Stephan202,
1
Czy to jest -or czy -o?
Stephane
1
@StephaneEybert: oba są w porządku, ale tylko ten drugi jest zgodny z POSIX (zgodnie ze stroną podręcznika).
Stephan202
16

To znajdzie wszystkie pliki .c lub .cpp w systemie Linux

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

Nie potrzebujesz uciekającego się nawiasu, chyba że wykonasz dodatkowe mody. Tutaj ze strony podręcznika mówią, że jeśli wzór pasuje, wydrukuj go. Być może próbują kontrolować drukowanie. W tym przypadku -print działa jako warunek i staje się warunkiem „AND”. Zapobiegnie to drukowaniu plików .c.

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

Ale jeśli podoba ci się oryginalna odpowiedź, możesz kontrolować drukowanie. To również znajdzie wszystkie pliki .c.

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

Ostatni przykład dla wszystkich plików źródłowych c / c ++

$ find . \( -name "*.c" -o -name "*.cpp"  -o -name "*.h" -o -name "*.hpp" \) -print
netskink
źródło
11

Miałem podobną potrzebę. To działało dla mnie:

find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print
Bkidd
źródło
3
Doskonały. Ale wydaje mi się to trochę dziwne, że nie działa bez()
pedrofurla
Chciałem znaleźć pliki, które pasują do * .c * .cpp lub * .cc Tylko z wzorcami o dwóch nazwach nie potrzebowałem parenów, ale z wzorami o trzech nazwach połączonymi z dwoma wzorami o find -name "*.cpp" -o -name "*.c" -o -name "*.cc" -print0musiałem użyć pary parenów, aby zgrupuj drugiego lub operatora. find -name "*.cpp" -o \( -name "*.c" -o -name "*.cc" \) -print0Możliwe, że -print0, które zawsze jest „prawdziwe”, wpłynęło na logikę.
mężczyzna z kosmosu w Cardiff,
5

Moje domyślne to:

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

Podobnie jak w przypadku mniej intencjonalnego findwykonania przez Brendana Longa i Stephana202 i in .:

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

PaSe
źródło
3
to nie jest poprawne użycie egrepwyrażenia regularnego, zamiast tego masz glob powłoki, w którym należy użyć wyrażenia regularnego. (Typowe findużycie to: find {directory} [options...] [action]gdzie, w zależności od impl, directorydomyślnie może .i actiondomyślnie jest -print, ale będę jawny.) Zamiast tego użyj czegoś takiego: find . -type f -print | egrep -i '\.java$|\.css$|\.cs$|\.sql$' Ale również, jako naprawdę szybka alternatywa find, można również spróbuj locatew podobny sposób (choć niekoniecznie aktualny, ponieważ wysyła zapytanie do wewnętrznej bazy danych o listę plików)
michael
2
#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done

proste, ale działa :)

mnrl
źródło
1

Musiałem usunąć wszystkie pliki z katalogów potomnych, z wyjątkiem niektórych plików. Dla mnie działały następujące (określone trzy wzory):

find . -depth -type f -not -name *.itp -and -not -name *ane.gro -and -not -name *.top -exec rm '{}' +
Cegła suszona na słońcu
źródło
1

Nawiasy klamrowe w obrębie wzorca \(\)są wymagane dla wzorca nazwy zor

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

Chociaż wzorzec nazwy z andoperatorem nie jest wymagany

find Documents -type f ! -name "*.py" -and ! -name "*.html" 
Chetabahana
źródło
0

Działa to na powłoce Korn AIX.

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

To szuka *.cbllub *.dmsktóre mają 1 dzień, tylko w bieżącym katalogu, pomijając podkatalogi.

Abdul M. Gill
źródło
0
find MyDir -iname "*.[j][p][g]"
+
find MyDir -iname "*.[b][m][p]"
=
find MyDir -iname "*.[jb][pm][gp]"
użytkownik7531934
źródło
2
Zauważ, że ta ostatnia będzie pasować do foo.jmg, ale żadna z dwóch pierwszych nie będzie.
copper.hat
0

Co powiesz na

ls {*.py,*.html}

Zawiera listę wszystkich plików z końcówkami .py lub .html w nazwach plików

Dr_Hope
źródło