Linux / Comando grep: cercare testo, regex e righe nei log
grep trova e stampa le righe che corrispondono a un modello nei file o nell’output di altri comandi. Puoi ignorare maiuscole e minuscole, selezionare le righe che non corrispondono, cercare nelle sottodirectory e mostrare il contesto. Per cercare una stringa letterale usa -F; per combinare espressioni regolari usa -E.
La forma di base è grep 'pattern' filename. Poiché il modello può contenere caratteri che hanno significati speciali nella shell, è più sicuro racchiuderlo abitualmente tra apici singoli.
Cos'è il comando grep?
grep legge l'input riga per riga e stampa le righe che corrispondono al modello. Il nome deriva dall'espressione del comando nell'editor di testo Unix ed, g/re/p, che significa trovare e stampare le righe che corrispondono a un'espressione regolare sull'intero intervallo.
Senza file indicati, una ricerca non ricorsiva legge l’ingresso standard: puoi quindi passarle l’output di un altro comando tramite una pipe. Con la ricerca ricorsiva GNU grep usa invece la directory corrente se non specifichi un percorso. La sintassi predefinita è l’espressione regolare di base (Basic Regular Expression, BRE); -E seleziona le espressioni regolari estese (Extended Regular Expression, ERE). Gli esempi seguenti si riferiscono a GNU grep; alcune opzioni differiscono in altre implementazioni.
Sintassi di base e prima ricerca
Questo è uno schema, non una riga da copiare: option, pattern e file sono segnaposto. Le parentesi quadre indicano gli argomenti facoltativi e i puntini consentono più file.
grep [option] 'pattern' [file...]
Per provare il primo comando, usa una nuova directory vuota e verifica che non contenga già app.log o worker.log: il seguente esempio li crea o li sovrascrive. Il piccolo log contiene due righe con ERROR e una riga con WARN.
cat > app.log <<'EOF'
INFO start
ERROR database unavailable
WARN slow response
ERROR retry failed ERROR
INFO completed
EOF
printf '%s\n' 'ERROR worker timeout' > worker.log
grep 'ERROR' app.log
Il risultato del primo comando contiene ERROR database unavailable e ERROR retry failed ERROR, in quest’ordine. Se specifichi entrambi i file, ogni riga selezionata è preceduta dal nome del file; anche worker.log produce una corrispondenza.
grep 'ERROR' app.log worker.log
Gli altri nomi di file e percorsi sono esempi da adattare: config.txt, app.conf, access.log, contacts.txt e i percorsi /etc richiedono file realmente esistenti e leggibili. Prova le ricerche ricorsive soltanto su una directory di esercizio o su un ambito scelto consapevolmente; non è necessario creare o modificare configurazioni di sistema.
Su Linux puoi filtrare i messaggi del kernel leggibili con dmesg. Il comando seguente cerca usb senza distinguere maiuscole e minuscole. L’accesso può essere limitato dalla politica del sistema: un errore di permesso non significa che non esistano messaggi USB; non modificare la politica per eseguire questa prova.
dmesg | grep -i 'usb'
Opzioni comuni di grep
| Opzione | Funzione | Esempi di utilizzo |
|---|---|---|
-i |
Cerca senza distinzione tra maiuscole e minuscole | grep -i 'error' app.log |
-v |
Seleziona le righe che non corrispondono | grep -v '^#' config |
-n |
Mostra i numeri delle righe nel risultato | grep -n 'TODO' main.c |
-w |
Cerca il modello come una parola intera | grep -w 'cat' words.txt |
-x |
Seleziona le righe che corrispondono interamente al modello | grep -x 'enabled' status.txt |
-F |
Considera il pattern come una stringa fissa, non come un'espressione regolare | grep -F 'a.b' data.txt |
-E |
Usa espressioni regolari estese | grep -E 'error|failed' app.log |
-r |
Cerca ricorsivamente nelle sottodirectory | grep -r 'listen' /etc/nginx |
-l |
Mostra solo i nomi dei file con corrispondenze | grep -rl 'deprecated' src |
-c |
Conta le righe selezionate per ciascun file | grep -c 'ERROR' app.log |
-A, -B, -C |
Mostra il contesto dopo, prima o intorno alle righe selezionate | grep -C 2 'panic' app.log |
Le opzioni sopra possono essere combinate. Ad esempio, grep -in 'error' app.log cercherà ignorando le maiuscole e minuscole e mostrerà anche i numeri di riga. Il comportamento dettagliato e le opzioni estese di GNU possono essere trovati nella documentazione ufficiale di GNU Grep.
Distinguere tra stringhe ed espressioni regolari
Cercare stringhe fisse con -F
I caratteri che hanno significati speciali nelle espressioni regolari, come punti, asterischi e parentesi, possono essere ricercati letteralmente usando -F. Nel comando seguente, il punto è trattato come un vero punto anziché come qualsiasi carattere.
grep -F '192.168.0.1' access.log
Con -F i punti sono letterali, ma la ricerca rimane per sottostringa: anche 192.168.0.10 contiene 192.168.0.1. Per un campo IP esatto devi delimitare il campo in base al formato reale del log; -xF è adatto solo se l’intera riga contiene quel valore.
Usare espressioni regolari estese con -E
L'uso di -E ti consente di utilizzare la sintassi delle espressioni regolari estese, come |, +, ?, e le parentesi, in modo più leggibile. L'esempio seguente trova le righe che contengono uno tra ERROR, WARN o FATAL.
grep -E 'ERROR|WARN|FATAL' app.log
In GNU grep, la differenza tra espressioni regolari di base ed estese risiede principalmente nella notazione. Se la compatibilità con altri ambienti è importante, controlla l'implementazione di grep e le opzioni supportate dal sistema di destinazione.
Specificare l’inizio e la fine di una riga
Il caret (^) rappresenta l'inizio di una riga, e il simbolo del dollaro ($) rappresenta la fine di una riga. Una riga vuota può essere trovata con ^$, che non ha caratteri tra l'inizio e la fine.
grep '^server' config.txt
grep 'completed$' job.log
grep '^$' notes.txt
Per escludere righe vuote e righe di commento da un file di configurazione, puoi applicare le due condizioni in sequenza come segue.
grep -v '^[[:space:]]*#' app.conf | grep -v '^[[:space:]]*$'
Restringere l’ambito della ricerca
Corrispondenza dell'intera parola e dell'intera riga
-w richiede che la corrispondenza sia delimitata da inizio/fine riga o da caratteri non appartenenti a una parola. In GNU grep lettere, cifre e underscore appartengono alle parole, con dettagli che dipendono dal locale: cat corrisponde in cat e cat-dog, ma non in category o cat_dog.
grep -w 'root' /etc/passwd
La ricerca di root in /etc/passwd non è limitata al primo campo: può selezionare root anche in altri campi. Per cercare il nome di login root all’inizio della riga usa grep '^root:' /etc/passwd.
-x seleziona una riga solo quando l'intera riga corrisponde esattamente al modello.
grep -x 'active' service-status.txt
Trovare righe che non corrispondono
-v inverte la selezione. L'esempio seguente stampa solo le righe che non contengono DEBUG.
grep -v 'DEBUG' app.log
Quando combinato con -i, puoi escludere senza considerare le maiuscole e le minuscole.
grep -iv 'debug' app.log
Ricerca di più modelli contemporaneamente
Usare -e più volte permette di specificare ogni modello separatamente. Non è necessario combinarli in un'unica espressione regolare complessa, rendendo più facile la lettura negli script.
grep -e 'ERROR' -e 'FATAL' app.log
Con -f, crea patterns.txt con un modello per riga, per esempio ERROR e FATAL su due righe distinte. I modelli sono alternative: basta che ne corrisponda uno. Una riga vuota è un modello vuoto e seleziona tutte le righe; un file completamente vuoto non contiene modelli e non seleziona nulla.
grep -f patterns.txt app.log
Cercare ricorsivamente in una directory
Differenza tra -r e -R
-r cerca ricorsivamente i file nella directory specificata. Segue i collegamenti simbolici specificati direttamente nella riga di comando, ma ignora i collegamenti simbolici incontrati durante le ricerche ricorsive.
grep -rn 'database_url' ./config
-R di GNU grep segue anche i collegamenti simbolici incontrati durante la visita. Non crea collegamenti: può attraversare un ciclo già presente o raggiungere percorsi esterni alla directory prevista. Usa questa opzione solo quando vuoi seguire tali destinazioni.
Inclusione ed esclusione dei tipi di file
--include limita la ricerca ai nomi di file che corrispondono al modello; --exclude salta i nomi corrispondenti. Sono modelli di nomi, non espressioni regolari. Racchiudili tra apici per evitare che la shell espanda gli asterischi prima di grep.
grep -rn --include='*.conf' 'timeout' /etc
grep -rn --exclude='*.min.js' 'deprecated' ./src
Per escludere directory specifiche, usa --exclude-dir.
grep -rn --exclude-dir='.git' --exclude-dir='node_modules' 'api_key' .
Mostrare solo i nomi dei file
Se hai bisogno di un elenco di file piuttosto che del contenuto corrispondente, usa -l. Ogni file smette di essere cercato dopo il primo match trovato, il che si adatta bene anche allo scopo.
grep -rl --include='*.html' 'jb-heading' .
Al contrario, per trovare solo file senza modelli corrispondenti, usa -L maiuscolo.
grep -rL --include='*.html' 'jb-heading' .
Leggere i risultati della ricerca
Mostrare numeri di riga e nomi dei file
-n mostra i numeri delle righe corrispondenti. Per mostrare anche il nome del file quando ne cerchi uno solo, usa -H di GNU grep; per nasconderlo, usa -h.
grep -nH 'listen' nginx.conf
Visualizzare le righe prima e dopo una corrispondenza
Se è difficile determinare la causa solo dalle linee di errore, utilizzare -A, -B, o -C per visualizzare le linee circostanti. Il numero indica quante linee aggiuntive vengono stampate.
grep -A 3 'ERROR' app.log
grep -B 2 'ERROR' app.log
grep -C 2 'ERROR' app.log
-A 3 aggiunge 3 linee dopo, -B 2 aggiunge 2 linee prima, e -C 2 aggiunge 2 linee prima e dopo.
Stampare solo le parti corrispondenti
-o mostra ogni parte corrispondente non vuota su una riga distinta. Le corrispondenze sono non sovrapposte: non conta tutte le possibili sovrapposizioni. Nell’esempio, contacts.txt deve contenere testo da cui estrarre sequenze di tre cifre, un trattino e quattro cifre; non è una convalida completa di numeri telefonici.
grep -oE '[0-9]{3}-[0-9]{4}' contacts.txt
Per evidenziare le corrispondenze nel terminale, puoi usare --color=auto. Quando invii l'output a un file o a un altro comando, usa auto o never per evitare che i caratteri di controllo del colore vengano mescolati.
Filtrare log e output dei comandi
Trovare errori nei log recenti
Per cercare solo l'intervallo recente invece dell'intero log, collegalo con tail.
tail -n 500 app.log | grep -iE 'error|failed|fatal'
La pipeline seguente mostra inizialmente le ultime dieci righe del file filtrate da grep e poi continua con le righe aggiunte. Per seguire soltanto le nuove aggiunte, usa tail -n 0 -F app.log al posto del primo comando. In primo piano, Ctrl+C interrompe il monitoraggio.
tail -F app.log | grep --line-buffered 'ERROR'
--line-buffered è un’opzione GNU che usa un buffer per riga per l’uscita di grep; non costringe il programma che produce i log a svuotare i propri buffer. Il comportamento di tail -F durante la rotazione è spiegato nella guida al comando tail di Linux.
Filtrare servizi e processi
Sui sistemi che usano systemd, systemctl list-unit-files elenca i file di unità e il loro stato di abilitazione, non soltanto i servizi attualmente in esecuzione. Il filtro seguente trova nginx come sottostringa delle righe; per l’uso negli script puoi aggiungere --no-pager a systemctl.
systemctl list-unit-files | grep 'nginx'
Per trovare processi, il manuale procps di pgrep distingue -f, che cerca nell’intera riga di comando, da -a, che la mostra insieme al PID (identificativo del processo). Il modello è un’espressione regolare: controlla comando e argomenti dei risultati, perché una corrispondenza non prova che il servizio funzioni correttamente.
pgrep -af 'nginx'
Contare le righe corrispondenti
-c stampa il numero di righe corrispondenti, non il numero di corrispondenze. Anche se una riga contiene il modello più volte, quella riga viene conteggiata solo una volta.
grep -c 'ERROR' app.log
Per contare le corrispondenze non vuote e non sovrapposte, separale con -o e passa l’output a wc -l. Nel piccolo app.log iniziale grep -c restituisce 2, mentre la pipeline seguente restituisce 3: la seconda riga selezionata contiene ERROR due volte.
grep -o 'ERROR' app.log | wc -l
Verifica dell'esistenza senza output
-q sopprime l’output standard e permette di controllare l’esistenza di una corrispondenza in una condizione. Per provare l’esempio, crea un file status.log con una riga ready: verrà stampato Servizio pronto. Anche not ready contiene la sottostringa ready; per una riga esattamente uguale usa -qx 'ready'. Un risultato diverso da zero fa saltare then sia in caso di assenza sia in caso di errore: questa semplice condizione non distingue i due casi.
if grep -q 'ready' status.log; then
echo 'Servizio pronto'
fi
Comprendere lo stato di uscita di grep
grep comunica i risultati della ricerca non solo tramite la stringa di output, ma anche attraverso lo stato di uscita. Tipicamente, restituisce 0 se ci sono righe corrispondenti, 1 se non ci sono righe corrispondenti, e 2 se non può leggere un file o c'è un problema di sintassi.
| Stato di uscita | Significato | Decisione negli script |
|---|---|---|
0 |
Una o più corrispondenze trovate | Elaborare come se la condizione fosse vera |
1 |
Nessuna corrispondenza trovata | Potrebbe essere un normale risultato della ricerca |
2 |
Si è verificato un errore | Controllare il file di input, i permessi o il modello |
La mancata corrispondenza è un esito di ricerca distinto da un errore: conserva subito $? se devi analizzarlo. Lo stato di una pipeline Bash è normalmente quello dell’ultimo comando, quindi un errore di dmesg, tail o grep può essere nascosto da un comando successivo. Valuta pipefail o PIPESTATUS quando devi verificare ogni fase, considerando anche l’uscita anticipata di grep -q. GNU grep -q può restituire 0 dopo una corrispondenza anche se un altro file ha dato errore; per rilevare tutti gli errori di lettura evita l’arresto anticipato e controlla stderr e stato finale.
Problemi comuni e soluzioni
Quando il modello inizia con un trattino
I modelli -ERROR come questo possono essere scambiati per opzioni. Metti il modello dopo --, che indica la fine delle opzioni.
grep -- '-ERROR' app.log
Quando appare il messaggio 'Binary file matches'
Se GNU grep determina che l'input è un file binario, potrebbe mostrare il messaggio invece delle righe corrispondenti. Se sei sicuro che sia effettivamente un file di testo, puoi trattarlo come testo usando -a.
grep -a 'ERROR' mixed-data.log
Al contrario, per escludere i file binari nelle ricerche ricorsive, puoi usare -I. Non usare sempre -a su dati binari sconosciuti, poiché potrebbero contenere caratteri di controllo che possono compromettere il tuo terminale.
Quando i risultati differiscono a causa dei caratteri speciali delle regex
Il punto corrisponde a qualsiasi singolo carattere e l'asterisco indica la ripetizione dell'espressione precedente nelle espressioni regolari. Se intendevi cercare una stringa semplice, usa -F, e se intendevi usare un'espressione regolare, racchiudi l'intero modello tra virgolette singole per evitare l'espansione della shell.
Quando le ricerche ricorsive sono troppo lente o producono troppi risultati
Restringi la directory di partenza per la ricerca ed escludi i file non necessari usando --include, --exclude e --exclude-dir. Per nascondere solo gli errori di permesso, potresti essere tentato di scartare tutti gli errori standard, ma farlo può farti perdere problemi importanti. Pertanto, è meglio controllare prima l'ambito della ricerca e i permessi dei file.
Domande frequenti
Per impostazione predefinita, grep distingue tra lettere maiuscole e minuscole?
Sì. La ricerca predefinita distingue tra maiuscole e minuscole. Per ignorare le maiuscole/minuscole, usa -i. Dovresti anche considerare che i risultati della gestione delle maiuscole/minuscole possono variare in base alle impostazioni locali (locale).
Qual è la differenza tra grep -r e grep -R?
In GNU grep, entrambi eseguono ricerche ricorsive, ma -R segue tutti i link simbolici incontrati durante la ricerca. Per le ricerche tipiche di codice sorgente o file di configurazione, -r è più facile da prevedere.
È un errore se non vengono trovati risultati della ricerca?
Non necessariamente. Se non ci sono corrispondenze, di solito restituisce uno stato di uscita di 1, mentre errori come il mancato accesso a un file o opzioni non valide sono distinti dallo stato 2.
Come faccio a trovare righe che contengono almeno uno di diversi termini di ricerca?
grep -E 'error|warning' filename utilizza l'operatore di alternanza nelle espressioni regolari estese, oppure puoi ripetere -e come grep -e 'error' -e 'warning' filename. Per trattare il termine di ricerca come una stringa semplice piuttosto che come un'espressione regolare, puoi anche usare -F.
Riepilogo
Per le ricerche generali nelle stringhe, è utile familiarizzare con grep -F; per condizioni multiple con espressioni regolari, grep -E; e per cercare in un'intera directory, grep -r. Per rendere i risultati più facili da interpretare, puoi usare -n e -C; se ti serve solo l'elenco dei file, utilizza -l; e per verificare l'esistenza negli script, usa -q.
Racchiudi i pattern tra virgolette singole, limita specificamente l'ambito delle ricerche ricorsive, e distingui tra stato di uscita 1 e stato di errore 2—questi sono elementi chiave per un utilizzo sicuro. Per esplorare insieme altri strumenti di base, consulta l’elenco dei comandi Linux più usati.




