Usa grep --exclude / - include la sintassi per non grep attraverso determinati file


780

Sto cercando la stringa foo=nei file di testo in un albero di directory. È su una macchina Linux comune, ho bash shell:

grep -ircl "foo=" *

Nelle directory ci sono anche molti file binari che corrispondono a "foo =". Poiché questi risultati non sono pertinenti e rallentano la ricerca, voglio che grep salti la ricerca di questi file (principalmente immagini JPEG e PNG). Come potrei farlo?

So che ci sono le opzioni --exclude=PATTERNe --include=PATTERN, ma qual è il formato del modello? La pagina man di grep dice:

--include=PATTERN     Recurse in directories only searching file matching PATTERN.
--exclude=PATTERN     Recurse in directories skip file matching PATTERN.

La ricerca su grep include , grep include exclude , grep exclude e le varianti non hanno trovato nulla di rilevante

Se esiste un modo migliore di eseguire il grepping solo in determinati file, sono pronto per questo; spostare i file offensivi non è un'opzione. Non riesco a cercare solo determinate directory (la struttura delle directory è un gran casino, con tutto ovunque). Inoltre, non riesco a installare nulla, quindi ho a che fare con strumenti comuni (come grep o la ricerca suggerita ).


13
Cordiali saluti, gli argomenti usati: -c contano le corrispondenze nel file -i maiuscole / minuscole -l mostra solo i file corrispondenti -r ricorsivi
Piskvor ha lasciato l'edificio il

68
Un modo più veloce per escludere le directory svn è --exclude-dir=.svn, quindi grep non le affronta affatto
orip

25
Un paio di punti pedanti che le persone potrebbero aver bisogno di sapere: 1. Nota la mancanza di virgolette in tutto il mondo qui: --exclude = ' . {Png, jpg}' non funziona (almeno con la mia versione GNU grep) perché grep non supporta {} nei suoi globs. Quanto sopra è espanso dalla shell a '--exclude = .png --exclude = *. Jpg' (supponendo che nessun file corrisponda nel CWD - altamente improbabile poiché normalmente non si iniziano nomi di file con '--exclude =') che a grep piace proprio bene. 2. --exclude è un'estensione GNU e non fa parte della definizione di grep di POSIX, quindi se si scrivono script usando questo si deve sapere che non funzioneranno necessariamente su sistemi non GNU.
IJW

2
Esempio completo di utilizzo di exclude-dir:grep -r --exclude-dir=var "pattern" .
Tisch

Risposte:


767

Usa la sintassi globbing della shell:

grep pattern -r --include=\*.{cpp,h} rootdir

La sintassi per --excludeè identica.

Nota che la stella è sfuggita a una barra rovesciata per impedire che venga espansa dalla shell (citandola, come --include="*.{cpp,h}", funzionerebbe altrettanto bene). Altrimenti, se nella directory di lavoro corrente fossero presenti file che corrispondessero al modello, la riga di comando si espanderebbe in qualcosa del genere grep pattern -r --include=foo.cpp --include=bar.h rootdir, che cercherebbe solo i file con nome foo.cppe bar.hche probabilmente non è quello che volevi.


8
Non so perché, ma ho dovuto citare il modello di inclusione in questo modo:grep pattern -r --include="*.{cpp,h}" rootdir
topek

6
@topek: buon punto - se hai dei file .cpp / .h nella tua directory corrente, la shell espanderà il glob prima di invocare grep, quindi finirai con una riga di comando come grep pattern -r --include=foo.cpp --include=bar.h rootdir, che cercherà solo i file chiamato foo.cppo bar.h. Se non ci sono file che corrispondono al glob nella directory corrente, la shell passa al glob per grep, il che lo interpreta correttamente.
Adam Rosenfield,

6
Ho appena capito che il glob è usato solo per abbinare il nome del file. Per escludere un'intera directory è necessaria --exclude-dirun'opzione. Stesse regole si applicano però. Viene associato solo il nome file della directory, non un percorso.
Krzysztof Jabłoński,

3
--includenon sembra funzionare dopo --exclude. Suppongo che non abbia nemmeno senso provare, tranne per il fatto che ho un aliasgrep con una lunga lista di --excludee --exclude-dir, che uso per cercare codice, ignorare librerie e scambiare file e cose. Lo avrei speratogrep -r --exclude='*.foo' --include='*.bar' avrebbe funzionato, così ho potuto limitare la mia aliasa --include='*.bar'solo, ma sembra ignorare l' --includee includere tutto ciò che non è un file .foo. Scambiare l'ordine di --includee --excludefunziona, ma ahimè, non è utile con il mio alias.
Michael Scheper,

1
come possiamo leggere la mente di qualcuno per ottenere regole per questo PATTERN. Mezz'ora non trovo alcuna descrizione di cosa stiano aspettando lì
Arkady,

221

Se vuoi solo saltare i file binari, ti suggerisco di guardare l' -Iopzione (maiuscola i). Ignora i file binari. Uso regolarmente il seguente comando:

grep -rI --exclude-dir="\.svn" "pattern" *

Cerca in modo ricorsivo, ignora i file binari e non cerca nelle cartelle nascoste di Subversion, qualunque sia il modello che voglio. Ho alias come "grepsvn" sulla mia scatola al lavoro.


1
Grazie, è molto utile per alcuni altri scenari che ho incontrato.
Piskvor lasciò l'edificio il

25
--exclude-dirnon è disponibile ovunque. la mia scatola RH al lavoro con GNU grep 2.5.1 non ce l'ha.
gcb,

Qualche suggerimento su cosa usare quando --exclude-dirnon è disponibile? In tutti i miei tentativi, --excludenon sembra adattarsi al conto.
JMTyler,

Puoi sempre scaricare l'ultima fonte grep da GNU ed eseguire una 'configurazione; rendere; sudo make install '. Questa è una delle prime cose che faccio su un Mac o su una distribuzione Linunx precedente.
Jonathan Hartley,

3
Esattamente quello di cui avevo bisogno. In realtà, io uso git. Quindi --exclude-dir="\.git". :-)
Ionică Bizău,

66

Dai un'occhiata a ack , che è progettato proprio per queste situazioni. Il tuo esempio di

grep -ircl --exclude=*.{png,jpg} "foo=" *

è fatto con ack come

ack -icl "foo="

perché ack non cerca mai nei file binari per impostazione predefinita e -r è attivo per impostazione predefinita. E se vuoi solo file CPP e H, allora fallo

ack -icl --cpp "foo="

Sembra bello, proverò la versione autonoma Perl la prossima volta, grazie.
Piskvor lasciò l'edificio il

5
Buona chiamata, non posso più vivere senza ack.
Probabilità,

1
stackoverflow.com/questions/667471/… - Questo ti permetterà di accedere a Windows, se è lì che stai eseguendo grep.
TamusJRoyce,

@Chance Forse vuoi silversearcher-ag , solo apt-getin Ubuntu :)
Justme0

da non confondere conawk
jasonleonhard il

35

grep 2.5.3 ha introdotto il parametro --exclude-dir che funzionerà nel modo desiderato.

grep -rI --exclude-dir=\.svn PATTERN .

Puoi anche impostare una variabile d'ambiente: GREP_OPTIONS = "- exclude-dir = .svn"

Io secondo di Andy voto per ack però, è il migliore.


7
+1 per menzionare il numero esatto di versione; Ho grep 2.5.1 e l'opzione exclude-dir non è disponibile
James,

25

L'ho trovato dopo molto tempo, è possibile aggiungere più inclusioni ed esclusioni come:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js

5
È meglio combinarli in un elenco come: --exclude = {pattern1, pattern2, pattern3}
Yasser Sinjab

12

Il comando suggerito:

grep -Ir --exclude="*\.svn*" "pattern" *

è concettualmente sbagliato, perché --exclude funziona sul nome di base. In altre parole, salterà solo il .svn nella directory corrente.


3
Sì, non funziona affatto per me. Quello che ha funzionato per me è stato: exclude-dir = .svn
Taryn East

2
@Nicola grazie! Mi sono strappato i capelli perché non funzionasse. Dimmi, c'è un modo per scoprirlo dalla manpage? Tutto ciò che dice è che corrisponde a "PATTERN". La manpage EDIT dice "file", come spiegato qui fixunix.com/unix/…
13

11

In grep 2.5.1 devi aggiungere questa linea al profilo ~ / .bashrc o ~ / .bash

export GREP_OPTIONS="--exclude=\*.svn\*"

9

Trovo che l'output di grep grep sia molto utile a volte:

grep -rn "foo=" . | grep -v "Binary file"

Tuttavia, ciò non gli impedisce di cercare i file binari.


10
È possibile utilizzare grep -Iper saltare i file binari.
Nathan Fellman,

l'ho fatto anche quando ero giovane ... ora lo so meglio e di fronte a un problema, la prima cosa è RTFM
gcb

grep grepping rimuoverà le alte luci di colore.
Max Li

7

Se non sei contrario all'utilizzo find, mi piace la sua -prunefunzionalità:

find [directory] \
        -name "pattern_to_exclude" -prune \
     -o -name "another_pattern_to_exclude" -prune \
     -o -name "pattern_to_INCLUDE" -print0 \
| xargs -0 -I FILENAME grep -IR "pattern" FILENAME

Nella prima riga, si specifica la directory che si desidera cercare. .(directory corrente) è un percorso valido, ad esempio.

Al 2 ° e 3 ° linee, uso "*.png", "*.gif", "*.jpg", e così via. Usa tanti di questi -o -name "..." -prunecostrutti quanti sono i tuoi schemi.

Sulla quarta riga, hai bisogno di un altro -o(specifica "o" a find), i modelli che vuoi, e hai bisogno di uno -printo -print0alla fine di esso. Se si desidera solo "tutto il resto", che rimane dopo la potatura la *.gif, *.pngecc immagini, quindi utilizzare -o -print0e il gioco è fatto con il 4 ° riga.

Infine, sulla 5a riga è la pipe in xargscui prende ciascuno di quei file risultanti e li memorizza in una variabile FILENAME. Passa quindi grepi -IRflag, il "pattern", e quindi FILENAMEviene espanso xargsper diventare quell'elenco di nomi di file trovati da find.

Per la tua domanda particolare, la dichiarazione potrebbe assomigliare a:

find . \
     -name "*.png" -prune \
     -o -name "*.gif" -prune \
     -o -name "*.svn" -prune \
     -o -print0 | xargs -0 -I FILES grep -IR "foo=" FILES


Un emendamento che suggerirei: includi -falsesubito dopo ognuno -prunecosì dimenticando di usare -print0o qualche tipo di execcomando in realtà non stampa i file che vuoi escludere: -name "*.png" -prune -false -o name "*.gif -prune -false...
OnlineCop

7

Su CentOS 6.6 / Grep 2.6.3, devo usarlo in questo modo:

grep "term" -Hnir --include \*.php --exclude-dir "*excluded_dir*"

Si noti la mancanza di segni di uguale "=" (altrimenti --include, --exclude, include-dire --exclude-dirvengono ignorati)



5

Sono un dilettante, garantito, ma ecco come appare il mio ~ / .bash_profile:

export GREP_OPTIONS = "- orl --exclude-dir = .svn --exclude-dir = .cache --color = auto" GREP_COLOR = '1; 32'

Nota che per escludere due directory, ho dovuto usare --exclude-dir due volte.



3

Se cerchi in modo non ricorsivo, puoi usare i pattern glop per abbinare i nomi dei file.

grep "foo" *.{html,txt}

include html e txt. Cerca solo nella directory corrente.

Per cercare nelle sottodirectory:

   grep "foo" */*.{html,txt}

Nelle directory secondarie:

   grep "foo" */*/*.{html,txt}

3

Nelle directory ci sono anche molti file binari. Non riesco a cercare solo determinate directory (la struttura delle directory è un gran casino). Esiste un modo migliore per eseguire il grepping solo in determinati file?

ripgrep

Questo è uno degli strumenti più veloci progettati per la ricerca ricorsiva della directory corrente. È scritto in Rust , costruito sulla base del motore regex di Rust per la massima efficienza. Controlla qui l'analisi dettagliata .

Quindi puoi semplicemente eseguire:

rg "some_pattern"

Rispetta il tuo .gitignoree salta automaticamente file / directory nascosti e file binari.

È ancora possibile personalizzare includere o escludere file e directory utilizzando -g/ --glob. Le regole dei globbing corrispondono ai .gitignoreglobs. Cerca man rgaiuto.

Per altri esempi, vedi: Come escludere alcuni file che non corrispondono a determinate estensioni con grep?

Su macOS, puoi installarlo tramite brew install ripgrep.


3

find e xargs sono i tuoi amici. Usali per filtrare l'elenco dei file piuttosto che --exclude di grep

Prova qualcosa del genere

find . -not -name '*.png' -o -type f -print | xargs grep -icl "foo="

Il vantaggio di abituarsi a questo è che è espandibile ad altri casi d'uso, ad esempio per contare le righe in tutti i file non png:

find . -not -name '*.png' -o -type f -print | xargs wc -l

Per rimuovere tutti i file non png:

find . -not -name '*.png' -o -type f -print | xargs rm

eccetera.

Come sottolineato nei commenti, se alcuni file possono contenere spazi nei loro nomi, utilizzare -print0e xargs -0invece.


1
Questo non funziona con nomi di file con spazi, ma questo problema può essere risolto facilmente usando print0 invece di print e aggiungendo l'opzione -0 a xargs.
Adam Rosenfield,

2

quegli script non risolvono tutto il problema ... Prova meglio:

du -ha | grep -i -o "\./.*" | grep -v "\.svn\|another_file\|another_folder" | xargs grep -i -n "$1"

questo script è molto meglio, perché usa espressioni regolari "reali" per evitare la ricerca di directory. basta separare i nomi di cartelle o file con "\ |" sul grep -v

divertirsi! trovato sulla mia shell Linux! XD


2

Guarda @ questo.

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags

2
Le cose che raggiungono circa questo obiettivo sono state trattate in altri post; per di più, questo è sbagliato, in quanto con varie opzioni di layout impostate confonderà i numeri di riga e cose del genere o escluderà le linee di contesto che erano desiderate.
Chris Morgan,

come puoi usare diverse opzioni "-v" contemporaneamente?
Apri la strada il

1

L' --binary-files=without-matchopzione GNU grepconsente di saltare i file binari. (Equivalente -Iall'interruttore menzionato altrove.)

(Ciò potrebbe richiedere una versione recente di grep; 2.5.3 ce l'ha, almeno.)


1

adatto per il file tcsh .alias:

alias gisrc 'grep -I -r -i --exclude="*\.svn*" --include="*\."{mm,m,h,cc,c} \!* *'

Mi ci è voluto un po 'per capire che la parte {mm, m, h, cc, c} NON dovrebbe essere racchiusa tra virgolette. ~ Keith


0

Per ignorare tutti i risultati binari di grep

grep -Ri "pattern" * | awk '{if($1 != "Binary") print $0}'

La parte awk filtra tutte le righe corrispondenti al file binario


-2

Prova questo:

  1. Crea una cartella denominata " --F" sotto currdir .. (o collega un'altra cartella lì rinominata in " --F" cioè double-minus-F.
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
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.