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.
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:
| metacarattere | significato |
|---|---|
| . | 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 \.
'…'). 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.
Ancore, classi, ripetizioni
Cominciamo con le ancore di inizio e fine riga, le più utili in assoluto:
$ 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:
$ 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".
$ echo -e "color\ncolour\ncolouur" | grep 'colou*r' color colour colouur # u* significa "zero o più u" — ammette anche zero u, quindi color matcha
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.
$ 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
\< 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:
$ grep -n '\<id\>' src/*.py src/user.py:14: id = uuid.uuid4() src/user.py:27: return self.id