Come ignorare alcuni nomi di file usando "trova"?


143

Uno dei miei comandi BASH preferiti è:

find . -name '*.*' -exec grep 'SearchString' {} /dev/null \;

che cerca il contenuto di tutti i file nella e sotto la directory corrente per il SearchString specificato. Come sviluppatore, questo è tornato utile a volte.

A causa del mio progetto attuale e della struttura della mia base di codice, tuttavia, mi piacerebbe rendere questo comando BASH ancora più avanzato non cercando alcun file che si trovi dentro o sotto una directory che contiene ".svn" o qualsiasi file che termina con ".html"

La pagina MAN per trovare mi ha confuso. Ho provato a usare -prune e mi ha dato un comportamento strano. Nel tentativo di saltare solo le pagine .html (per iniziare), ho provato:

find . -wholename './*.html' -prune -exec grep 'SearchString' {} /dev/null \;

e non ho ottenuto il comportamento che speravo. Penso che potrei perdere il punto di -prune. Ragazzi, potete aiutarmi?

Grazie


1
Fyi: findnon è un comando bash
incorporato

1
Puoi cercare nel file congrep -rl 'SearchString'
emanuele il

@emanuele Ciao, benvenuto su SuperUser (e sulla rete Stack Exchange). Questa è una domanda che ho posto e alla quale è stata data risposta 2 anni e mezzo fa. In genere, se desideri aggiungere una risposta alla domanda, scorri verso il basso e rispondendo lì, anziché in un commento. Poiché questa domanda ha già una risposta accettata (quella con il segno di spunta verde), è improbabile, tuttavia, che la tua risposta attirerà molta attenzione. PER TUA INFORMAZIONE.
Cody S,

1
Ciao, non è una risposta alla tua domanda. È solo un suggerimento, come hai affermato nel preambolo che usa findper cercare all'interno di un file.
emanuele,

2
FWIW, -name '*.*'non trova tutti i file: solo quelli con un .nel loro nome (l'uso di *.*è in genere un DOS-ism, mentre in Unix normalmente si usa solo *per quello). Per tutti loro corrispondere in realtà, è sufficiente rimuovere l'argomento del tutto: find . -exec .... O se vuoi applicare grep solo ai file (e saltare le directory), allora fallo find . -type f -exec ....
Stefan,

Risposte:


197

Puoi usare la funzione negate (!) Di find per non abbinare i file con nomi specifici:

find . ! -name '*.html' ! -path '*.svn*' -exec grep 'SearchString' {} /dev/null \;

Quindi, se il nome termina in .html o contiene .svn in qualsiasi punto del percorso, non corrisponderà e quindi l'esecuzione non verrà eseguita.


1
Devo ancora specificare -name ' . 'da qualche parte lì dentro? Lo farei prima o dopo le negazioni?
Cody S

L'intenzione della tua *.*partita era garantire che corrispondesse solo ai file contenenti un .? Trova corrisponderà a tutti i file in assenza di una namedirettiva, quindi quanto sopra corrisponderà a tutto tranne html e svn
Paul

5
Penso che tu voglia -wholename '*.svn*'piuttosto che -name.
fuenfundachtzig,

2
Sì, sì, in modo che le .svndirectory siano escluse dai risultati della ricerca.
fuenfundachtzig,

1
@Noumenon ! -name '.'dovrebbe escludere .dai risultati della ricerca.
Paolo,

11

Ho avuto lo stesso problema da molto tempo e ci sono diverse soluzioni che possono essere applicabili in diverse situazioni:

  • ack-grepè una sorta di "sviluppatore grep" che per impostazione predefinita salta directory di controllo versione e file temporanei. La manpagina spiega come cercare solo tipi di file specifici e come definirne uno proprio .
  • grepLe opzioni --excludee le --exclude-diropzioni proprie possono essere utilizzate molto facilmente per saltare globs di file e singole directory (purtroppo non ci sono problemi per le directory).
  • find . \( -type d -name '.svn' -o -type f -name '*.html' \) -prune -o -print0 | xargs -0 grep ... dovrebbe funzionare, ma le opzioni di cui sopra sono probabilmente meno seccanti nel lungo periodo.

9

Il seguente findcomando elimina le directory i cui nomi contengono .svn , sebbene non scenda nella directory, il nome del percorso eliminato viene stampato ... ( -name '*.svn'è la causa!) ..

È possibile filtrare i nomi delle directory tramite: grep -d skipche salta silenziosamente tali "nomi delle directory" di input.

Con GNU grep, puoi usare -Hinvece di /dev/null. Come un piccolo problema secondario: \+può essere molto più veloce di \;, ad es. per 1 milione di file a una riga, il suo utilizzo \;ha richiesto 4m20s , il suo utilizzo \+ha richiesto solo 1,2s .

Il metodo seguente utilizza xargsinvece di -exece presuppone che non vi siano nuove righe \nin nessuno dei nomi dei file . Come usato qui, xargsè molto simile a quello di find \+.

xargspuò passare nomi di file che contengono spazi consecutivi modificando il delimitatore di input '\n'con l' -dopzione.

Questo esclude le directory i cui nomi contengono .svn e greps solo i file che non terminano .html.

find . \( -name '*.svn*' -prune  -o ! -name '*.html' \) |
   xargs -d '\n' grep -Hd skip 'SearchString'

1
Grazie per aver sottolineato la \+variante dell'azione -exec. Evviva per lievi problemi collaterali!
Christian Long,

Naturalmente, poiché +non è un carattere speciale per la shell, non è necessario digitare \prima di esso.
Scott,
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.