modello `find -name` che corrisponde a più modelli


335

Stavo cercando di ottenere un elenco di tutti i file python e html in una directory con il comando find Documents -name "*.{py,html}".

Poi è arrivata la pagina man:

Le parentesi graffe all'interno del modello ('{}') non sono considerate speciali (ovvero, trova. -Name 'foo {1,2}' corrisponde a un file chiamato foo {1,2}, non ai file foo1 e foo2.

Poiché fa parte di una pipe-chain, vorrei essere in grado di specificare a quali estensioni corrisponde in fase di esecuzione (senza hardcoding). Se find non riesce a farlo, un perl one-liner (o simile) andrebbe bene.

Modifica: la risposta che mi è venuta in mente include tutti i tipi di schifezze, ed è anche un po 'lunga, quindi l'ho pubblicata come risposta al prurito originale che stavo cercando di grattare. Sentiti libero di hackerarlo se hai soluzioni migliori.



Un'utilità spesso trascurata e sottoutilizzata è anche locate, sebbene con l'avvertenza che l'aggiornamento internob potrebbe non essere aggiornato. Ma è veloce.
michael

Sto votando per chiudere questa domanda come off-topic perché appartiene a Unix e Linux
Dan Dascalescu l'

Risposte:


481

Usa -o, che significa "o":

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

Dovresti costruire quella riga di comando a livello di codice, il che non è così facile.

Stai usando bash (o Cygwin su Windows)? Se lo sei, dovresti essere in grado di farlo:

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

che potrebbe essere più facile da costruire a livello di codice.


3
Sto usando zsh, che, come regola generale, supporta tutti i bashismi e altro ancora.
Xiong Chiamiov,

12
Zsh supporta la **ricerca ricorsiva; Bash lo supporta solo nelle versioni 4.0 e successive e solo con shopt -s globstar.
effimero il

2
Quanti -o argomenti puoi avere? Ho un elenco potenzialmente ampio di file .gcda (dati di copertura) da compilare
Jasper Blues

40
È necessario circondare le due -names tra parentesi, se si utilizza -exec. Ad esempiofind Documents \( -name "*.py" -o -name "*.html" \) -exec file {} \;
artbristol

2
Il commento di @artbristol è molto rilevante se, ad esempio, stai aggiungendo un -print0per gestire i nomi di file con spazi.
nimrodm,

63

Alcune edizioni di find, principalmente su sistemi linux, possibilmente su altre supportano anche le opzioni -regex e -regextype, che trova file con nomi corrispondenti al regex.

per esempio

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

dovrebbe fare il trucco nell'esempio sopra. Tuttavia, questa non è una funzione di ricerca POSIX standard e dipende dall'implementazione.


1
interessante ma più complesso delle altre risposte
m1k3y3,

12
Più semplice: find . -regex ".*\.\(py\|html\)$"funziona perché trova le impostazioni predefinite delle espressioni regolari in stile Emacs, che sono leggermente diverse, quindi non è necessario specificare il regextype.
robru,

2
Se hai molte espressioni -regextype posix-egrepè utile (altrimenti dovrai sfuggire a molti personaggi). Questo è il comando find che ho usato per un dist-hook che crea un zip di distribuzione di Windows (trova i file da cambiare e in-file li cambia 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

È possibile aggiungere a livello di -namecodice più clausole, separate da -or:

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

Oppure, fai un semplice ciclo invece:

for F in Documents/*.{py,html}; do ...something with each '$F'... ; done

@ user2284570: quindi non ci sono *.pyfile o hai una versione dispari di find. Il comando sopra elencato funziona bene.
Stephan202,

No, sto usando -iname. Restituisce i *.pyfile solo se lo scrive nell'ultima posizione (così iname *.htmlè la prima espressione) . Uso il comando su Debian.
user2284570

Stai usando le virgolette? Questo è molto importante.
Stephan202,

1
È un -o o un -o?
Stephane,

1
@StephaneEybert: o va bene, ma solo quest'ultimo è conforme a POSIX (secondo la pagina man).
Stephan202,

16

Questo troverà tutti i file .c o .cpp su Linux

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

Non hai bisogno della parentesi di escape a meno che tu non stia facendo alcune mod aggiuntive. Qui dalla pagina man stanno dicendo se lo schema corrisponde, stampalo. Forse stanno cercando di controllare la stampa. In questo caso, l'impronta funge da condizionale e diventa un condizionale "AND". Impedirà la stampa di qualsiasi file .c.

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

Ma se ti piace la risposta originale puoi controllare la stampa. Questo troverà anche tutti i file .c.

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

Un ultimo esempio per tutti i file sorgente c / c ++

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

11

Avevo un bisogno simile. Questo ha funzionato per me:

find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print

3
Perfetto. Ma trovo un po 'strano che non funzioni senza()
pedrofurla,

Volevo trovare file che corrispondessero a * .c * .cpp o * .cc Con solo modelli a due nomi non avevo bisogno di parentesi ma con modelli a tre nomi uniti a modelli a due -o find -name "*.cpp" -o -name "*.c" -o -name "*.cc" -print0dovevo usare una coppia di parentesi per raggruppare il secondo o l'operatore. find -name "*.cpp" -o \( -name "*.c" -o -name "*.cc" \) -print0È possibile che -print0, che è sempre "vero", abbia influito sulla logica.
cardiff space man

5

Il mio valore predefinito è stato:

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

Come l' findesecuzione meno intuitiva di processo di Brendan Long e Stephan202 et al .:

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


3
non è un uso corretto di egrepregexp, piuttosto, hai un glob shell in cui dovrebbe essere usato un regexp. (Inoltre, l' finduso tipico è: find {directory} [options...] [action]dove, a seconda di impl, directorypotrebbe essere predefinito .e actionpredefinito -print, ma sarò esplicito.) Quindi, invece, usa qualcosa del tipo: find . -type f -print | egrep -i '\.java$|\.css$|\.cs$|\.sql$' Ma anche, come alternativa molto veloce a find, si potrebbe anche provare locatein modo simile (anche se non necessariamente aggiornato, poiché richiede un db interno per un elenco di file)
michael

2
#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done

semplice ma funziona :)


1

Avevo bisogno di rimuovere tutti i file nelle directory secondarie ad eccezione di alcuni file. Il seguente ha funzionato per me (tre modelli specificati):

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

1

Le parentesi graffe all'interno del modello \(\)sono necessarie per il modello nome conor

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

Mentre per il modello di nome con andoperatore non è richiesto

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

0

Funziona con la shell AIX korn.

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

Questo è alla ricerca *.cblo *.dmsche hanno 1 giorno di età, solo nella directory corrente, saltando le sottodirectory.


0
find MyDir -iname "*.[j][p][g]"
+
find MyDir -iname "*.[b][m][p]"
=
find MyDir -iname "*.[jb][pm][gp]"

2
Nota che quest'ultimo corrisponderà a foo.jmg ma nessuno dei primi due lo farà.
Copper.hat il

0

Che dire

ls {*.py,*.html}

Elenca tutti i file che terminano con .py o .html nei loro nomi di file

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.