Come usare il comando "grep" per trovare il testo comprese le sottodirectory


373

Voglio trovare tutti i file che contengono una specifica stringa di testo. Il grepcomando funziona, ma non so come usarlo per ogni directory (posso farlo solo per la mia directory corrente). Ho provato a leggere man grep, ma non ha dato alcun aiuto.


grep -RIn <yor pattern> * Ricerca dalle directory correnti in giù in tutti i file di testo. Non sono sicuro di come fare la mia ricerca in modo ricorsivo in modelli di file come * .C con solo grep

1
--include="*.C"Carattere jolly con opzione, @ user311346, grazie a @Lekensteyn.
Bob Stein,

Utilizzare la combinazione find e grep per cercare in modo ricorsivo una stringa nelle directory correnti e in tutte le directory secondarie. Controlla questo wilddiary.com/find-files-contain-my-text
Drona

Risposte:


487

Sarebbe meglio usare

grep -rl "string" /path

dove

  • -rL' --recursiveopzione (o ) viene utilizzata per attraversare anche tutte le sottodirectory di /path, mentre
  • -lL' --files-with-matchesopzione (o ) viene utilizzata per stampare solo i nomi dei file dei file corrispondenti e non le righe corrispondenti (ciò potrebbe anche migliorare la velocità, dato che grepinterrompere la lettura di un file alla prima corrispondenza con questa opzione).

13
In realtà se "stringa" è un modello di testo da trovare, è meglio usare quella funzionalità, altrimenti qualcuno può affrontare problemi quando la stringa contiene un punto o un carattere speciale che ha significato nelle espressioni regolari e non solo un punto che dovrebbe essere trovato come una stringa , come è. Quindi userei -rlFswitch, -Fper "stringa fissa" (e non regexp - per esempio). Ovviamente, se l'attività stava usando regexps, allora mi scusi. Certo, la stessa teoria anche senza -r, vedo spesso che le persone assumono "testo" nelle ricerche grep e che può causare problemi a quelli speciali che significano qualcosa come regexp.
LGB

4
C'è anche la -ibandiera che ignora il caso.
Marco Ceppi

3
Vorrei solo mostrare l' --recursiveopzione, ci sono tonnellate di opzioni e scenari di utilizzo di cui si può parlare. Ho iniziato dalla risposta accettata da @dmityugov e modificato per funzionare senza find.
enzotib,

1
@NN: fatto :-)
enzotib

3
@ScottBiggs: con l'opzione--include '*.h'
enzotib,

167

Se stai cercando le linee corrispondenti nei file, il mio comando preferito è:

grep -Hrn 'search term' path/to/files
  • -H causa la stampa del nome file (implicito quando si cercano più file)
  • -r fa una ricerca ricorsiva
  • -n provoca la stampa del numero di riga

path/to/filespuò essere .quello di cercare nella directory corrente

Ulteriori opzioni che trovo molto utili:

  • -Iignora i file binari (complemento: -atratta tutti i file come testo)
  • -Ftrattare search termcome un'espressione letterale, non regolare
  • -i fare una ricerca senza distinzione tra maiuscole e minuscole
  • --color=alwaysper forzare i colori anche durante le tubazioni less. Per creare lesscolori di supporto, è necessario utilizzare l' -ropzione:

    grep -Hrn search . | less -r
    
  • --exclude-dir=dirutile per escludere directory come .svne .git.

Esempio di output


13
-Hsu una cartella è ridondante, se esiste più di un file, come è probabile. In effetti, la pagina man dice-H, --with-filename: Print the file name for each match. This is the default when there is more than one file to search.
enzotib

Non lo sapevo, ha sempre funzionato come mi aspettavo. È il mio comando predefinito quando si cercano file.
Lekensteyn,

1
C'è un modo per considerare i file solo con un'estensione, diciamo, .a (e combinare questo con -r)?
user2413

6
@ user2413 Prova--include '*.*'
Lekensteyn,

1
@alper Trygrep --exclude='*~' ...
Lekensteyn,

24

Credo che tu possa usare qualcosa del genere:

find /path -type f -exec grep -l "string" {} \;

Spiegazione dai commenti

findè un comando che ti consente di trovare file e altri oggetti come directory e collegamenti nelle sottodirectory di un determinato percorso. Se non si specifica una maschera che i nomi file devono soddisfare, enumera tutti gli oggetti directory.

  • -type f specifica che dovrebbe elaborare solo file, non directory ecc.
  • -exec grepspecifica che per ogni file trovato, dovrebbe eseguire il comando grep, passando il suo nome file come argomento, sostituendolo {}con il nome file

3
Solo per chi non lo sapesse, l'aggiunta -name '*.py'limita le corrispondenze ai file che terminano con ".py".
Daniel F,

Mi piace che questo includa client che non hanno implementato -R nel loro comando grep.
Aviose,

Se vuoi stampare la riga corrispondente E il nome del file, esegui exec come:... -exec bash -c 'grep -r "mystring" {} && echo {}' \;
Donn Lee

qual è il perf relativo semplicemente usando grep direttamente?
Jonathan,

19

Il mio comando predefinito è

grep -Rin string *

Uso una R maiuscola perché la lsusa come ricorsiva. Poiché grep accetta entrambi, nessun motivo per non usarlo.

EDIT: per HVNSweeting, apparentemente -Rseguirà symlink dove -rnon lo faranno.


1
Per cercare anche in file nascosti, esegui shopt -s dotglob(ricorda -scome "set"). Fai attenzione quando rimuovi i file. Se hai abilitato dotglob, rm -r *rimuove tutto nella directory corrente, ma anche la directory sopra di essa perché ..corrisponde. Per disabilitare dotglob, utilizzare shopt -u dotglob("unset"). Le modifiche sono temporanee, ma si applicano solo alla shell corrente.
Lekensteyn,

Mi sono dimenticato di questo. C'è un modo per impostarlo su una riga? qualcosa di simile shopt -s dotglob & <grep cmd> & shopt -y dotglobsolo più conveniente? In questo modo non dovremo preoccuparci di ripristinarlo
user606723

Inoltre, è probabilmente più facile da usare grep -Rin string .nella maggior parte di questi casi. Uso solo * perché sembra venire più naturalmente.
user606723

1
se fai grep ricorsivo, allora puoi semplicemente iniziare da "." invece di "*". non è necessario dotglob.
Michał Šrajer,

1
vota questo, una cosa che non menziona nella manpage è Rche seguirà i collegamenti simbolici, rno
HVNSweeting

12

Se sei disposto a provare qualcosa di nuovo, prova ack. Il comando per cercare ricorsivamente la directory corrente stringè:

ack string

L'installazione è abbastanza semplice:

curl http://betterthangrep.com/ack-standalone > ~/bin/ack && chmod 0755 !#:3

(A condizione che tu abbia già la directory ~/bined è preferibilmente nella tua PATH.)


2
O semplicemente apt-get install ack-grep (, e aggiungi alias ack = ack-grep al tuo .bashrc)
markijbema

Cosa fanno gli ultimi parametri del chmodcomando? Sono specifici chmodo correlati a bash (la !#:3parte)?
Elliott Darfink,

@ElliottDarfink Questo sta usando la funzione di cronologia di Bash - !è un designatore di eventi . Sono abbastanza potenti per evitare ripetizioni. !#:3fa riferimento al terzo token della riga di comando finora, ovvero ~/bin/ackin questo caso.
Konrad Rudolph,

4

Il comando rgrep è dedicato a tale esigenza

Se non disponibile, puoi ottenerlo in questo modo

mkdir -p ~/bin
cd ~/bin
wget http://sdjf.esmartdesign.com/files/rgrep
chmod +x rgrep

Puoi impostare direttamente le opzioni grep predefinite come descritto sopra.

Personalmente uso

[[  ${#args} -lt 5 && "${args//[[:space:]]/}" == "-i" ]] && args="-Hin"
args="${args:--Hns} --color=auto"

argomento correlato: come utilizzare sempre rgrep con il colore


rgrep è fornito dal pacchetto grep che è installato di default in Ubuntu.
Karel,

2

Aggiornamento 2:

Questa riga di comandi utilizza finde greprisolve il problema:

$ find path_to_search_in -type f -exec grep -in searchString {} 2> /dev/null +

--color=<always or auto> per output colorato:

$ find path_to_search_in -type f \
            -exec grep --color=always -in searchString {} 2>/dev/null +

Esempio:

$ find /tmp/test/ -type f -exec grep --color=auto -in "Search string" {} 2>/dev/null +

Un esempio eseguito nell'istantanea di seguito: snap1


Aggiornamento 1:

Puoi provare il seguente codice; come funzione nel tuo .bashrco .bash_aliaseso in uno script:

wherein () 
{ 
    for i in $(find "$1" -type f 2> /dev/null);
    do
        if grep --color=auto -i "$2" "$i" 2> /dev/null; then
            echo -e "\033[0;32mFound in: $i \033[0m\n";
        fi;
    done
}

Uso: wherein /path/to/search/in/ searchkeyword

esempio:

$ wherein ~/Documents/ "hello world"

(Nota: come suggerito nei commenti seguenti di @enzotib, questo non funziona con file / directory inclusi gli spazi nei loro nomi.)


Posta originale

Per cercare la stringa e generare solo quella riga con la stringa di ricerca:

$ for i in $(find /path/of/target/directory -type f); do \
    grep -i "the string to look for" "$i"; done

per esempio:

$ for i in $(find /usr/share/applications -type f); \
    do grep -i "web browser" "$i"; done

Per visualizzare il nome file contenente la stringa di ricerca:

$ for i in $(find /path/of/target/directory -type f); do \
    if grep -i "the string to look for" "$i" > /dev/null; then echo "$i"; fi; done;

per esempio:

$ for i in $(find /usr/share/applications -type f); \
    do if grep -i "web browser" "$i" > /dev/null; then echo "$i"; \
    fi; done;

Errore nei nomi dei file contenenti spazi. Il fallimento è nascosto dal fatto che stderr non è mostrato.
enzotib,

@enzotib grazie per averlo sottolineato .. che è ancora irrisolto per la funzione specificata .. Ho aggiunto un altro one-liner però ..
preciso

Ora la risposta è simile a quella di @dmityugov.
enzotib,

sì, ma in questo senso la maggior parte delle risposte in questa pagina se controlli sono simili rispetto a quelle che usano grep, accanto a quello che è il sottoinsieme che usa findcon grep... ma se devi accettare diversi switch e modifiche come una risposta distinta, probabilmente anche il mio si adatterà qui .. o sei diverso? l'ultimo aggiornamento fa quello che mi piacerebbe nella mia ricerca: nomi di file con righe con chiave di ricerca e riga n. troppo :) e output colorato e filtro errori per una migliore leggibilità ..
preciso

2

grep( GNU o BSD )

Puoi usare lo grepstrumento per cercare ricorsivamente la cartella corrente con un -rparametro, come:

grep -r "pattern" .

Nota: -r- Cerca ricorsivamente le sottodirectory.

Per cercare all'interno di file specifici, è possibile utilizzare una sintassi globbing come:

grep "class foo" **/*.c

Nota: utilizzando l' opzione globbing ( **), esegue la scansione di tutti i file in modo ricorsivo con estensione o modello specifici. Per abilitare questa sintassi, eseguire: shopt -s globstar. È inoltre possibile utilizzare **/*.*per tutti i file (esclusi quelli nascosti e senza estensione) o qualsiasi altro motivo.

Se hai l'errore che l'argomento sia troppo lungo, considera di restringere la ricerca o usa la findsintassi invece come:

find . -name "*.php" -execdir grep -nH --color=auto foo {} ';'

In alternativa usa ripgrep.

ripgrep

Se stai lavorando su progetti più grandi o file di grandi dimensioni, dovresti ripgrepinvece utilizzare , come:

rg "pattern" .

Controlla i documenti, i passaggi di installazione o il codice sorgente nella pagina del progetto GitHub .

E 'molto più veloce rispetto a qualsiasi altro strumento come GNU / BSD grep , ucg, ag, sift, ack, pto simili, dal momento che è costruito sulla cima di motore regex di Rust , che utilizza automi a stati finiti, SIMD e ottimizzazioni letterali aggressivi per rendere la ricerca molto veloce.

Supporta i pattern ignorati specificati nei .gitignorefile, quindi un singolo percorso di file può essere abbinato a più pattern glob contemporaneamente.


È possibile utilizzare i parametri comuni come:

  • -i - Ricerca insensibile.
  • -I - Ignora i file binari.
  • -w - Cerca le parole intere (al contrario della corrispondenza parziale delle parole).
  • -n - Mostra la linea della tua partita.
  • -C/ --context(ad es. -C5): aumenta il contesto, in modo da visualizzare il codice circostante.
  • --color=auto - Contrassegna il testo corrispondente.
  • -H - Visualizza il nome del file in cui è stato trovato il testo.
  • -c- Visualizza il conteggio delle righe corrispondenti. Può essere combinato con -H.

1

Faccio questo usando xargs, un comando molto sottovalutato

find ./ -type f -print0 | xargs -0 grep 'string_you_are_looking_for'

find ./ ti dà un elenco ricorsivo di tutti i file in una cartella corrente, quindi lo instrada a xargs che esegue il comando grep su ciascuno di quei file


4
L'uso xargssenza l' -print0opzione to finde l' -0opzione to xargsè deprecato, fallirà sui nomi di file contenenti spazi.
enzotib,

@enzotib Ho modificato la risposta come mi hai suggerito.- Per favore, rivedi e se hai bisogno di modifica e correzione, sarò felice di ri-editing da te. grazie
αғsнιη il

1
@KasiyA: ora va bene, rimosso il mio downvote.
enzotib,

0

So che ci sono molte risposte qui, ma ecco un'alternativa se desideri aggiungere altre restrizioni durante la ricerca dei file:

find . -type f -exec grep --quiet string_to_look_for {} ';' -print

Questo funziona perché greprestituirà 0 se ha trovato un risultato, 1 altrimenti. Ad esempio puoi trovare file di dimensioni pari a 1 MB e contenenti qualcosa:

find . -type f -exec grep --quiet string_to_look_for {} ';' -size 1M -print

Per molteplici requisiti probabilmente si desidera utilizzare il flag di ottimizzazione -Opresente in GNU grep.


0

Uno script (trova nel codice) per cercare in C, codice CPP:

#!/bin/sh

find . \( -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" \) -type f -print0 | xargs -0 grep --color -n "$1"

Uso:

find-in-code "search string"
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.