$ grep — corso
Lezione 07 di 10

Output, formattazione e colori

Una riga di output di grep non è "una riga": è la materia prima per il comando successivo nella pipe. Saperla modellare — solo la parte interessante, senza nomi di file, con un separatore preciso — è ciò che trasforma grep in uno strumento di estrazione.

Teoria

Modellare cosa grep stampa

Tre flag controllano la forma dell'output:

flagcosa fa
-ostampa solo la parte della riga che matcha, non l'intera riga
-hnasconde il nome del file (utile con più file)
-Hforza la stampa del nome del file (anche con un solo file)
--color=...colora il match: auto, always, never
-Z, --nulltermina i nomi file con NUL invece che newline

--color=auto è il default sensato: colore se l'output va al terminale, nessun codice colore se va in pipe (così non sporchi il testo che passa a un altro comando). Se vuoi vedere i colori anche in pipe (per esempio con less -R), serve --color=always.

Sui sistemi moderni --color=auto è già il comportamento di default tramite l'alias alias grep='grep --color=auto' che molte distro inseriscono in ~/.bashrc. Se i colori non compaiono, controlla che l'alias ci sia.
Pratica

Estrarre, non solo trovare

Il salto concettuale è -o. Senza, grep mostra la riga; con, grep diventa un estrattore. Esempio: prendiamo tutti gli indirizzi email da un testo qualsiasi.

estrarre email
$ cat > contatti.txt <<'EOF'
Mario Rossi è raggiungibile a mario@esempio.it
Anna scrive da anna.bianchi@lavoro.com, oppure a.bianchi@gmail.com
Per assistenza: support@dominio.org (24/7)
EOF

# senza -o : tutta la riga
$ grep -E '[A-Za-z0-9._]+@[A-Za-z0-9.-]+' contatti.txt
Mario Rossi è raggiungibile a mario@esempio.it
Anna scrive da anna.bianchi@lavoro.com, oppure a.bianchi@gmail.com
Per assistenza: support@dominio.org (24/7)

# con -o : solo le email, una per riga
$ grep -oE '[A-Za-z0-9._]+@[A-Za-z0-9.-]+' contatti.txt
mario@esempio.it
anna.bianchi@lavoro.com
a.bianchi@gmail.com
support@dominio.org

Ora che ogni email è su una riga separata, possiamo concatenare altri comandi Unix: quante email uniche ci sono per dominio?

grep + cut + sort + uniq
$ grep -oE '[A-Za-z0-9._]+@[A-Za-z0-9.-]+' contatti.txt \
    | cut -d@ -f2 \
    | sort | uniq -c | sort -rn
   1 lavoro.com
   1 gmail.com
   1 esempio.it
   1 dominio.org

Conteggio dei match (non delle righe!). Ricorda: -c conta le righe che matchano, non le occorrenze. Per contare i match veri si usa -o + wc -l:

contare i match veri
$ echo "ciao ciao ciao mondo" | grep -c ciao
1          # una sola riga, anche se "ciao" ricorre 3 volte

$ echo "ciao ciao ciao mondo" | grep -o ciao | wc -l
3          # vere occorrenze del match
Trucco

Forzare i colori dentro less per leggere log enormi

Quando vai in pipe verso less i colori spariscono, perché grep capisce che non sta scrivendo a un terminale. Risultato: la lettura di un log lungo diventa faticosa, hai perso il riferimento visivo al match. La combinazione che risolve è:

match evidenziato anche in less
$ grep --color=always -n ERROR /var/log/syslog | less -R

--color=always fa inserire i codici ANSI nell'output anche in pipe; less -R li interpreta correttamente invece di stamparli come caratteri. Sulla maggior parte dei sistemi moderni puoi anche scrivere less con la variabile d'ambiente LESS=R impostata e perdere il -R.

Salvataggio dei colori in un file: usa lo stesso trucco per esportare ricerche colorate da incollare in una mail o in un ticket. Apri il file di destinazione con cat o less -R: i colori si vedono. Non aprirlo invece con un editor di testo, vedrebbe gli escape ANSI come pattume.

Trucco gemello: grep -Z + xargs -0 per gestire nomi file con spazi quando passi l'elenco a un altro comando. Senza, gli spazi spaccherebbero xargs:

nomi file con spazi, gestiti bene
$ grep -rlZ "vecchia API" . | xargs -0 sed -i 's/vecchia API/nuova API/g'

-Z separa i nomi file con il carattere NUL; xargs -0 li legge sapendo che il separatore è quello e non lo spazio. È il modo robusto di fare una sostituzione massiva su tutti i file trovati.