Salta al contenuto principale

grep: il comando che trova ago e pagliaio (e molto altro)

Inviato da tuxsa il

Se passi un po' di tempo davanti a un terminale Linux, prima o poi ti trovi a dover cercare qualcosa: una riga in un log da centomila righe, una variabile di configurazione dimenticata, un indirizzo IP in mezzo a un file di testo. Per tutto questo esiste grep, uno degli strumenti più vecchi e più utili del mondo Unix.

Cos'è grep

grep legge un testo (da uno o più file, oppure dallo standard input) e stampa solo le righe che corrispondono a un modello di ricerca. Il nome viene da un comando dell'editor ed: g/re/p, cioè global / regular expression / print. Nasce nel 1973 ed è stato scritto da Ken Thompson. Su Linux trovi la versione GNU, che fa parte del progetto GNU ed è software libero.

La sintassi di base è:

grep [opzioni] "modello" [file...]

Primi esempi

Cerchiamo la parola errore in un file di log:

grep "errore" /var/log/syslog

Ogni riga che contiene la parola viene stampata. Semplice.

Se il file è protetto, serve sudo:

sudo grep "Failed password" /var/log/auth.log

Utilissimo per vedere chi sta provando a indovinare le password SSH del tuo server.

Le opzioni da conoscere

Le opzioni rendono grep potente. Queste sono quelle che uso più spesso.

-i: ignora maiuscole e minuscole

grep -i "salerno" articolo.txt

Trova Salerno, SALERNO e salerno.

-n: mostra il numero di riga

grep -n "listen" /etc/nginx/nginx.conf

Perfetto quando devi poi aprire il file con un editor e andare dritto alla riga giusta.

-v: inverti la ricerca

Mostra le righe che non contengono il modello. Ottimo per togliere i commenti da un file di configurazione:

grep -v "^#" /etc/ssh/sshd_config

-c: conta le corrispondenze

grep -c "404" access.log

Restituisce quante righe contengono 404, senza stamparle.

-r (o -R): ricerca ricorsiva nelle cartelle

grep -rn "password" /var/www/miosito/

Cerca in tutti i file sotto la cartella. Molto comodo per scovare dove è definita una funzione in un progetto, o per controllare di non aver lasciato credenziali in chiaro nel codice.

-l: elenca solo i nomi dei file

grep -rl "TODO" ~/progetti/

-w: parola intera

grep -w "log" file.txt

Trova log ma non login né catalogo.

-A, -B, -C: contesto attorno alla riga

grep -C 3 "segmentation fault" debug.log

Stampa la riga trovata più 3 righe prima e 3 dopo. -A è after, -B è before, -C è context (entrambi). Fondamentale quando analizzi i log, perché l'errore da solo spesso non basta: serve capire cosa è successo prima.

-o: stampa solo la parte che corrisponde

grep -oE "[0-9]{1,3}(\.[0-9]{1,3}){3}" access.log

Estrae solo gli indirizzi IP (in modo approssimativo) invece di stampare tutta la riga.

Espressioni regolari

Il vero punto di forza di grep sono le espressioni regolari (regex). Qualche simbolo essenziale:

SimboloSignificato
^inizio riga
$fine riga
.un carattere qualsiasi
*zero o più ripetizioni del carattere precedente
[abc]uno dei caratteri tra parentesi
[0-9]una cifra

Con -E (regex estese, equivalente a egrep) hai anche +, ?, | e le parentesi di raggruppamento senza dover usare backslash:

# righe che iniziano con "Error" o "Warning"
grep -E "^(Error|Warning)" app.log

# indirizzi email, in modo grossolano
grep -oE "[A-Za-z0-9._-]+@[A-Za-z0-9.-]+\.[a-z]{2,}" contatti.txt

Se invece cerchi una stringa letterale che contiene caratteri speciali (punti, parentesi, asterischi), usa -F:

grep -F "192.168.1.1" file.txt

Senza -F il punto varrebbe "qualsiasi carattere". Con -F il testo è preso alla lettera, ed è anche più veloce.

-P abilita le regex compatibili con Perl (lookahead, \d e così via), ma dipende dalla build di grep installata.

grep in pipeline: il suo habitat naturale

Il bello di grep è che si combina con gli altri comandi tramite la pipe |.

Trovare un processo:

ps aux | grep firefox

Cercare un pacchetto installato:

dpkg -l | grep -i owncast

Controllare la cronologia dei comandi:

history | grep ffmpeg

Filtrare l'output di journalctl:

journalctl -u nginx --since today | grep -i "error"

Classifica degli IP più attivi in un access log:

grep -oE "^[0-9.]+" access.log | sort | uniq -c | sort -rn | head

Contare quanti file .md contengono una parola:

grep -rl "trasparenza" --include="*.md" . | wc -l

L'opzione --include (e il suo contrario --exclude, oppure --exclude-dir=.git) limita la ricerca a certi tipi di file. Con -r evita di setacciare binari e cartelle inutili.

Quando usare grep

grep è la scelta giusta quando:

  • devi filtrare o cercare testo in file, log o output di altri comandi;
  • vuoi verificare rapidamente se qualcosa è presente (basta controllare l'exit code: 0 se trova, 1 se non trova);
  • scrivi script di shell e ti serve una condizione basata sul contenuto di un file;
  • lavori su un server remoto via SSH, dove grep c'è sempre e non devi installare nulla.

Esempio d'uso in uno script:

if grep -q "PermitRootLogin yes" /etc/ssh/sshd_config; then
    echo "Attenzione: login root via SSH abilitato"
fi

L'opzione -q (quiet) non stampa nulla: restituisce solo l'exit code.

Quando non basta

grep è uno strumento per cercare, non per modificare né per elaborare campi.

  • Per sostituire del testo usa sed.
  • Per lavorare su colonne e campi (per esempio la terza colonna di un CSV) usa awk o cut.
  • Per grandi codebase esistono alternative più veloci e più comode, come ripgrep (rg), che rispetta .gitignore, ignora i binari ed è parallelizzato. Un'altra è ag (The Silver Searcher).
  • Per dati strutturati come JSON, è meglio jq: usare grep su JSON funziona finché non incontri un a capo inatteso.

Piccole trappole

  • Le virgolette contano. Metti sempre il modello tra virgolette: senza, la shell può interpretare caratteri come * o $ prima che arrivino a grep.
  • grep e se stesso. In ps aux | grep firefox compare anche la riga del comando grep. Trucco classico: grep "[f]irefox", oppure usa direttamente pgrep firefox.
  • File binari. Se grep dice Binary file matches, aggiungi -a per trattarlo come testo, oppure -I per ignorare i binari.
  • Codifiche. Con testi in UTF-8 e lingue con accenti, controlla che la tua locale (echo $LANG) sia coerente, altrimenti -i può comportarsi in modo strano con le lettere accentate.

Riepilogo veloce

ObiettivoComando
Cerca una parolagrep "parola" file
Ignora maiuscolegrep -i
Numero di rigagrep -n
Righe senza la parolagrep -v
Ricerca nelle cartellegrep -rn "parola" cartella/
Solo nomi dei filegrep -rl
Contesto attornogrep -C 3
Regex estesegrep -E
Testo letteralegrep -F
Solo la parte trovatagrep -o

grep ha più di cinquant'anni e fa ancora esattamente quello per cui è stato progettato: una cosa sola, fatta bene. Impararne le dieci opzioni principali ti fa risparmiare ore di lavoro, che tu stia analizzando i log di un server, controllando la configurazione di un servizio o cercando in un archivio di documenti. È anche un ottimo punto di partenza per entrare nel mondo delle espressioni regolari, che ti torneranno utili in sed, awk, nei linguaggi di programmazione e negli editor di testo.

Per approfondire: man grep, oppure grep --help per un promemoria rapido.