$ grep — corso
Lezione 04 di 10

Espressioni regolari estese

Con -E sblocchi quantificatori, alternanza e gruppi: la sintassi diventa quella che la maggior parte delle persone si aspetta da una regex moderna. È quasi sempre quello che vuoi usare.

Teoria

Quello che BRE non aveva

ERE è l'acronimo di Extended Regular Expression. Si attiva con il flag -E, oppure usando il comando storico egrep (oggi deprecato ma ancora presente). Aggiunge quattro cose centrali rispetto a BRE:

simbolosignificato
+una o più ripetizioni del precedente
?zero o una occorrenza (rende opzionale)
{n}esattamente n ripetizioni
{n,m}tra n e m ripetizioni
a|balternanza: a oppure b
(…)gruppo

In BRE gli stessi simboli si possono ottenere col backslash: \+, \?, \{n,m\}, \|, \(…\). Ma è una sintassi pesante e poco leggibile. Per qualsiasi regex non banale conviene aggiungere -E e finita lì.

Regola pratica: quando un pattern contiene anche solo +, ?, | o gruppi, scrivi grep -E. Più chiaro per chi legge, più portabile tra script.
Pratica

Numeri, versioni, indirizzi

Uno dei classici: trovare numeri di versione in un file di sorgente o di configurazione. Una versione è qualcosa come 1.2.3 — cifre, punto, cifre, punto, cifre.

trovare versioni
$ cat > release.txt <<'EOF'
release 2.4.1
patch 2.4.2
versione iniziale 0.1
ultimo: 12.0.5-rc
EOF

# una o più cifre, punto, una o più cifre, punto, una o più cifre
$ grep -E '[0-9]+\.[0-9]+\.[0-9]+' release.txt
release 2.4.1
patch 2.4.2
ultimo: 12.0.5-rc

# anche le versioni a due numeri (0.1) — il terzo gruppo è opzionale
$ grep -E '[0-9]+\.[0-9]+(\.[0-9]+)?' release.txt
release 2.4.1
patch 2.4.2
versione iniziale 0.1
ultimo: 12.0.5-rc

L'alternanza con | è preziosissima per cercare più cose con una sola passata. Cerchiamo errori, warning e info in un log unico:

più pattern in una volta
$ cat > app.log <<'EOF'
[INFO]  avvio applicazione
[WARN]  cache vuota
[INFO]  connessione db
[ERROR] connessione fallita
[DEBUG] retry in 5s
EOF

$ grep -E 'ERROR|WARN' app.log
[WARN]  cache vuota
[ERROR] connessione fallita

Quantificatore preciso con {n,m}. Esempio: trovare codici postali italiani (esattamente 5 cifre) o americani (5, o 5-4):

ripetizioni precise
$ echo -e "Milano 20121\nRoma 00100\nNYC 10001-1234\ncodice 999" \
    | grep -E '\<[0-9]{5}(-[0-9]{4})?\>'
Milano 20121
Roma 00100
NYC 10001-1234
Trucco

Eliminare le righe vuote (e i commenti) da un file

Capita di continuo: vuoi leggere un file di configurazione pulito, senza tutte le righe vuote e i commenti che lo riempiono. Con grep -E -v si fa in una riga, ed è una delle combinazioni più riusabili che esistano:

vedere solo la configurazione "viva"
$ cat /etc/ssh/sshd_config
#  $OpenBSD: sshd_config,v 1.104 ...
# questa è una riga di commento

Port 22
# AddressFamily any
PermitRootLogin no

# righe non vuote e non commento
$ grep -Ev '^\s*(#|$)' /etc/ssh/sshd_config
Port 22
PermitRootLogin no

Il pattern ^\s*(#|$) dice: a inizio riga, eventuali spazi/tab, poi o un # (commento) o la fine della riga (riga vuota). Con -v chiediamo l'opposto: tutto ciò che non è quello.

Trasformalo in un alias: mettilo nel tuo ~/.bashrc o ~/.zshrc come alias conf='grep -Ev "^\s*(#|$)"' — d'ora in poi conf /etc/nginx/nginx.conf ti mostrerà la configurazione effettiva, senza rumore. Il tempo che risparmierai a leggere file di configurazione lunghi è enorme.

Una variante per chi gestisce server: stessa logica applicata a tutta una cartella con -r (lezione 5) per vedere d'un colpo tutte le direttive attive di un servizio.