$ grep — corso
Lezione 03 di 10

Espressioni regolari di base

Le regex sono il vero linguaggio di grep. Le basic regular expressions di default sono limitate ma sufficienti per quasi tutto; e capirle bene è il modo per non essere mai sorpresi quando un pattern non funziona come ci si aspetta.

Teoria

BRE: i metacaratteri fondamentali

Grep, di default, interpreta il pattern come Basic Regular Expression (BRE). I metacaratteri principali sono pochi e vale la pena memorizzarli:

metacaratteresignificato
.un qualsiasi singolo carattere
*zero o più ripetizioni di ciò che precede
^inizio riga
$fine riga
[abc]uno tra a, b, c
[^abc]un carattere diverso da a, b, c
[a-z]un carattere nell'intervallo
\< \>confine di parola (inizio / fine)

Quattro cose non sono in BRE e fanno inciampare anche utenti esperti: +, ?, | e () sono caratteri normali in BRE — bisogna usare -E (lezione 4) per attivarli, oppure farli precedere da \.

La regola d'oro: il pattern va sempre tra apici singoli ('…'). Le doppie virgolette lasciano alla shell il diritto di interpretare $, backslash e altri segni — e finisci per cercare qualcosa di diverso da quello che credi.
Pratica

Ancore, classi, ripetizioni

Cominciamo con le ancore di inizio e fine riga, le più utili in assoluto:

ancore
$ cat > note.txt <<'EOF'
# Lista spesa
mela
- banana
- pera
# Fine
EOF

# righe che iniziano con #
$ grep '^#' note.txt
# Lista spesa
# Fine

# righe che iniziano con -
$ grep '^-' note.txt
- banana
- pera

# righe esattamente uguali a "mela" (combinando ^ e $)
$ grep '^mela$' note.txt
mela

Classi di caratteri con le parentesi quadre. Tipico: trovare righe che contengono cifre, o solo lettere maiuscole:

classi di caratteri
$ echo -e "Ciao\nfile123\nABC\n42" | grep '[0-9]'
file123
42

# solo righe interamente in maiuscolo
$ echo -e "Ciao\nABC\nfile" | grep '^[A-Z]*$'
ABC

# righe che NON contengono cifre
$ echo -e "Ciao\nfile123\nABC" | grep -v '[0-9]'
Ciao
ABC

Il punto . e la stella * in coppia sono il modo BRE per dire "qualcosa, qualunque cosa". Attenzione: * da sola non vuol dire "qualsiasi cosa" come nelle wildcard della shell — vuol dire "zero o più di quello che ho appena scritto".

il punto e la stella
$ echo -e "color\ncolour\ncolouur" | grep 'colou*r'
color
colour
colouur

# u* significa "zero o più u" — ammette anche zero u, quindi color matcha
Trucco

I confini di parola \< e \>

Avevamo visto nella lezione precedente che -w impone che il pattern matchi una parola intera. Quel comportamento è anche esprimibile direttamente nella regex, con i word boundary di BRE: \< per l'inizio di parola e \> per la fine. Vale la pena imparare entrambe le forme perché ti danno controllo separato sui due lati.

word boundary
$ printf '%s\n' "cat" "category" "tomcat" "scat" | grep 'cat'
cat
category
tomcat
scat

# solo cat come parola intera
$ printf '%s\n' "cat" "category" "tomcat" "scat" | grep '\<cat\>'
cat

# solo parole che INIZIANO con cat (ma possono continuare)
$ printf '%s\n' "cat" "category" "tomcat" "scat" | grep '\<cat'
cat
category

# solo parole che FINISCONO con cat
$ printf '%s\n' "cat" "category" "tomcat" "scat" | grep 'cat\>'
cat
tomcat
scat
Compatibilità: \< e \> funzionano in GNU grep e in BSD grep, ma sono una vecchia estensione. Una forma più moderna e equivalente è \b (entrambi i lati), disponibile in grep -P: la vedremo nella lezione 8.

Usalo, per esempio, per cercare il nome di una variabile in un sorgente senza catturare nomi più lunghi:

cercare 'id' senza beccare 'idle' e 'midi'
$ grep -n '\<id\>' src/*.py
src/user.py:14:    id = uuid.uuid4()
src/user.py:27:    return self.id