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.
Modellare cosa grep stampa
Tre flag controllano la forma dell'output:
| flag | cosa fa |
|---|---|
| -o | stampa solo la parte della riga che matcha, non l'intera riga |
| -h | nasconde il nome del file (utile con più file) |
| -H | forza la stampa del nome del file (anche con un solo file) |
| --color=... | colora il match: auto, always, never |
| -Z, --null | termina 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.
--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.
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.
$ 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 -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:
$ 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
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 è:
$ 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.
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:
$ 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.