103.7 Lezione 1
Certificazione: |
LPIC-1 |
---|---|
Versione: |
5.0 |
Argomento: |
103 Comandi GNU e Unix |
Obiettivo: |
103.7 Cercare file di testo utilizzando espressioni regolari |
Lezione: |
1 di 2 |
Introduzione
Gli algoritmi di ricerca delle stringhe sono ampiamente utilizzati in diversi compiti di elaborazione dati, tanto che i sistemi operativi Unix-like hanno la loro onnipresente implementazione: Espressioni regolari (Regular expressions), spesso abbreviate in REs. Le espressioni regolari sono costituite da sequenze di caratteri che costituiscono un modello generico utilizzato per individuare e talvolta modificare una sequenza corrispondente in una stringa di caratteri più grande. Le espressioni regolari espandono notevolmente la capacità di:
-
Scrivere regole di analisi per le richieste nei server HTTP, in particolare nginx.
-
Scrivere script che convertono set di dati basati su testo in un altro formato.
-
Ricercare le occorrenze di interesse in voci di diario o documenti.
-
Filtrare i documenti di markup, mantenendo il contenuto semantico.
L’espressione regolare più semplice contiene almeno un atomo. Un atomo, così chiamato perché è l’elemento base di un’espressione regolare, è solo un carattere che può avere o meno un significato speciale. La maggior parte dei caratteri ordinari non sono ambigui, mantengono il loro significato letterale, mentre altri hanno un significato speciale:
.
(punto)-
Il carattere corrisponde a un qualsiasi carattere.
^
(segno d’omissione)-
Il carattere corrisponde all’inizio della linea.
$
(simbolo del dollaro)-
Il carattere corrisponde alla fine della linea.
Per esempio, l’espressione regolare bc
, composta dagli atomi letterali b
e c
, può essere trovata nella stringa abcd
, ma non può essere trovata nella stringa a1cd
. D’altra parte, l’espressione regolare .c
può essere trovata in entrambe le stringhe abcd
e a1cd
, poiché il punto .
corrisponde a qualsiasi carattere.
Gli atomi del segno di omissione e del dollaro vengono utilizzati quando interessano solo le corrispondenze all’inizio o alla fine della stringa. Per questo motivo sono anche chiamati anchors. cd
può essere trovato in abcd
, ma ^cd
no. Allo stesso modo, ab
può essere trovato in abcd
, ma ab$
non può. Il simbolo di omissione ^
è un carattere letterale tranne quando all’inizio e $
è un carattere letterale tranne quando alla fine dell’espressione regolare.
Espressioni tra Parentesi Quadre
Esiste un altro tipo di atomo denominato bracket expression. Sebbene non sia un singolo carattere, le parentesi []
(incluso il loro contenuto) sono considerate un singolo atomo. Un’espressione tra parentesi quadre di solito è solo un elenco di caratteri letterali racchiusi da []
, facendo sì che l’atomo corrisponda a ogni singolo carattere dell’elenco. Per esempio, l’espressione [1b]
può essere trovata in entrambe le stringhe abcd
e a1cd
. Per specificare i caratteri a cui l’atomo non deve corrispondere, l’elenco deve iniziare con ^
, come in [^ 1b]
. È anche possibile specificare intervalli di caratteri nelle espressioni di parentesi. Per esempio, [0-9]
corrisponde alle cifre da 0 a 9 e [a-z]
corrisponde a qualsiasi lettera minuscola. Gli intervalli devono essere utilizzati con cautela, poiché potrebbero non essere coerenti tra le diverse impostazioni locali.
Gli elenchi di espressioni tra parentesi quadre accettano anche classi invece di singoli caratteri e intervalli. Le classi sono:
[:alnum:]
-
Rappresenta un carattere alfanumerico.
[:alpha:]
-
Rappresenta un carattere alfabetico.
[:ascii:]
-
Rappresenta un carattere che si adatta al set di caratteri ASCII.
[:blank:]
-
Rappresenta un carattere vuoto, ovvero uno spazio o una tabulazione.
[:cntrl:]
-
Rappresenta un carattere di controllo.
[:digit:]
-
Rappresenta una cifra (da 0 a 9).
[:graph:]
-
Rappresenta qualsiasi carattere stampabile tranne lo spazio.
[:lower:]
-
Rappresenta un carattere minuscolo.
[:print:]
-
Rappresenta qualsiasi carattere stampabile compreso lo spazio.
[:punct:]
-
Rappresenta qualsiasi carattere stampabile che non sia uno spazio o un carattere alfanumerico.
[:space:]
-
Rappresenta i caratteri spazi vuoti: spazio, avanzamento modulo (
\f
), nuova riga (\n
), ritorno a capo (\r
), tabulazione orizzontale (\t
) e tabulazione verticale (\v
). [:upper:]
-
Rappresenta un carattere maiuscolo.
[:xdigit:]
-
Rappresenta cifre esadecimali (da 0 a F)
Le classi di caratteri possono essere combinate con singoli caratteri e intervalli, ma non possono essere utilizzate come punto finale di un intervallo. Inoltre, le classi di caratteri possono essere utilizzate solo nelle espressioni di parentesi, non come un atomo indipendente al di fuori delle parentesi.
Quantificatori
La portata di un atomo, sia di un singolo carattere che di una parentesi, può essere regolata utilizzando un quantificatore. I quantificatori atomici definiscono le sequenze atomiche, ovvero le corrispondenze si verificano quando nella stringa viene trovata una ripetizione contigua per l’atomo. La sottostringa corrispondente alla corrispondenza è chiamata parte. Tuttavia, i quantificatori e altre caratteristiche delle espressioni regolari vengono trattati in modo diverso a seconda dello standard utilizzato.
Come definito dallo standard POSIX, ci sono due forme di espressioni regolari: espressioni regolari “basic” ed espressioni regolari “extended”. La maggior parte dei programmi relativi al testo in qualsiasi distribuzione Linux convenzionale supporta entrambe le forme, quindi è importante conoscere le loro differenze al fine di evitare problemi di compatibilità e scegliere l’implementazione più adatta per l’attività prevista.
Il quantificatore *
ha la stessa funzione sia nelle RE di base che in quelle estese (l’atomo ricorre zero o più volte) ed è un carattere letterale se appare all’inizio dell’espressione regolare o se è preceduto da un back slash \
. Il quantificatore del segno più ` selezionerà i "pezzi" contenenti uno o più corrispondenze di atomi in sequenza. Con il quantificatore del punto interrogativo `?`, Si verificherà una corrispondenza se l'atomo corrispondente appare una volta o se non compare affatto. Se preceduto da un _back slash_ `\`, il loro significato speciale non viene considerato. Le espressioni regolari di base supportano anche i quantificatori `
e ?
, Ma devono essere preceduti da un back slash. A differenza delle espressioni regolari estese, +
e ?
sono di per sé caratteri letterali nelle espressioni regolari di base.
Limiti
Un bound è un quantificatore di atomi che, come suggerisce il nome, consente a un utente di specificare limiti di quantità precisi per un atomo. Nelle espressioni regolari estese un limite può apparire in tre forme:
{i}
-
L’atomo deve apparire esattamente
i
volte (i
è un numero intero). Per esempio,[[:blank:]]{2}
corrisponde esattamente a due caratteri vuoti. {i,}
-
L’atomo deve apparire almeno
i
volte (i
è un numero intero). Per esempio,[[:blank:]]{2,}
corrisponde a qualsiasi sequenza di due o più caratteri vuoti. {i,j}
-
L’atomo deve apparire almeno
i
volte e al massimoj
volte (i
ej
sono numeri interi,j
è maggiore dii
). Per esempio,xyz{2,4}
corrisponde alla stringa xy seguita da due a quattro del caratterez
.
In ogni caso, se una sottostringa corrisponde a un’espressione regolare e anche una sottostringa più lunga che inizia nello stesso punto corrisponde, verrà considerata la sottostringa più lunga.
Anche le espressioni regolari di base supportano i limiti, ma i delimitatori devono essere preceduti da \
: \{
e \}
. Di per sé, {
e }
vengono interpretati come caratteri letterali. Una \{
seguita da un carattere diverso da una cifra è un carattere letterale, non l’inizio di un limite.
Rami e Riferimenti all’Indietro
Le espressioni regolari di base differiscono dalle espressioni regolari estese anche per un altro aspetto importante: un’espressione regolare estesa può essere suddivisa in remi (branches), ciascuna un’espressione regolare indipendente. I rami sono separati da |
e l’espressione regolare combinata corrisponderà a tutto ciò che corrisponde a uno qualsiasi dei rami. Per esempio, he|him
corrisponderà se nella stringa in esame si trova la sottostringa he
o him
. Le espressioni regolari di base interpretano |
come un carattere letterale. Tuttavia, la maggior parte dei programmi che supportano le espressioni regolari di base consentiranno i rami con \ |
.
Un’espressione regolare estesa racchiusa tra ()
può essere utilizzata in un riferimento all’indietro. Per esempio: ([[:digit:]])\1
corrisponderà a qualsiasi espressione regolare che si ripete almeno una volta, perché \1
nell’espressione è il riferimento all’indietro al pezzo corrispondente alla prima parentesi sottoespressione. Se nell’espressione regolare esiste più di una sottoespressione tra parentesi, è possibile fare riferimento a \2
,\3
e così via.
Per le RE di base, le sottoespressioni devono essere racchiuse tra \(
e \)
, con (
e )
da sole saranno considerate come caratteri ordinari. L’indicatore di riferimento all’indietro viene utilizzato come nelle espressioni regolari estese
Ricerca con Espressioni Regolari
Il vantaggio immediato offerto dalle espressioni regolari è quello di migliorare le ricerche sui filesystem e nei documenti di testo. L’opzione -regex
del comando find
permette di testare ogni percorso in una gerarchia di directory rispetto a un’espressione regolare. Per esempio:
$ find $HOME -regex '.*/\..*' -size +100M
Cerca file più grandi di 100 megabyte (100 unità di 1048576 byte), ma solo nei percorsi all’interno della directory home dell’utente che contengono una corrispondenza con .*/\..*
, cioè un / .
circondato da qualsiasi altro numero di caratteri. In altre parole, verranno elencati solo i file nascosti o i file all’interno di directory nascoste, indipendentemente dalla posizione di /.
, nel percorso corrispondente. Per le espressioni regolari senza distinzione tra maiuscole e minuscole, dovrebbe essere utilizzata l’opzione -iregex
:
$ find /usr/share/fonts -regextype posix-extended -iregex '.*(dejavu|liberation).*sans.*(italic|oblique).*' /usr/share/fonts/dejavu/DejaVuSansCondensed-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansCondensed-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSans-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSans-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-Oblique.ttf /usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf /usr/share/fonts/liberation/LiberationSans-Italic.ttf
In questo esempio, l’espressione regolare contiene rami (scritti in stile extended) per elencare solo file di font specifici nella gerarchia di directory /usr/share/fonts
. Le espressioni regolari estese non sono supportate di default, ma find
permette di abilitarle con -regextype posix-extended
o -regextype egrep
. Lo standard RE predefinito per find
è findutils-default, che è virtualmente un clone di espressioni regolari di base.
Spesso è necessario passare l’output di un programma al comando less
quando non si adatta allo schermo. Il comando less
divide il suo input in pagine, una schermata alla volta, consentendo all’utente di navigare facilmente nel testo su e giù. Inoltre, less
consente anche a un utente di eseguire ricerche basate su espressioni regolari. Questa caratteristica è particolarmente importante perché less
è il paginatore predefinito usato per molte attività quotidiane, come l’ispezione delle voci del diario o la consultazione delle pagine di manuale. Quando si legge una pagina di manuale, per esempio, premendo il tasto / si aprirà un prompt di ricerca. Questo è uno scenario tipico in cui le espressioni regolari sono utili, poiché le opzioni di comando sono elencate subito dopo un margine di pagina nel layout generale della pagina del manuale. Tuttavia, la stessa opzione potrebbe apparire molte volte nel testo, rendendo irrealizzabili le ricerche letterali. Indipendentemente da ciò, digitando ^[[:blank:]]-o
— o più semplicemente: ^
-o
— nel prompt di ricerca si salterà immediatamente all’opzione della sezione -o
(se esiste) dopo aver premuto Invio, consentendo così di consultare più rapidamente la descrizione di un’opzione.
Esercizi Guidati
Quale espressione regolare estesa corrisponderebbe a qualsiasi indirizzo email, come `info@example.org`?
+
-
Quale espressione regolare estesa corrisponderebbe solo a qualsiasi indirizzo IPv4 nel formato standard a quattro punti, come
192.168.15.1
? -
Come può essere usato il comando
grep
per elencare il contenuto del file/etc/services
, scartando tutti i commenti (righe che iniziano con#
)? -
Il file
domains.txt
contiene un elenco di nomi di dominio, uno per riga. Come sarebbe usato il comandoegrep
per elencare solo i domini.org
o.com
?
Esercizi Esplorativi
-
Dalla directory corrente, in che modo il comando
find
userebbe un’espressione regolare estesa per cercare tutti i file che non contengono un suffisso di file standard (i nomi di file non terminano con.txt
o.c
, per esempio)? -
Il comando
less
è il paginatore predefinito per visualizzare file di testo lunghi nell’ambiente shell. Digitando/
è possibile inserire un’espressione regolare nel prompt di ricerca per passare alla prima corrispondenza trovata. Per rimanere nella posizione del documento corrente ed evidenziare solo le corrispondenze, quale combinazione di tasti deve essere inserita al prompt di ricerca? -
In
less
, come sarebbe possibile filtrare l’output in modo che vengano visualizzate solo le righe che corrispondono a un’espressione regolare?
Sommario
Questa lezione tratta del supporto generale di Linux alle espressioni regolari, uno standard ampiamente utilizzato le cui capacità di corrispondenza dei modelli sono supportate dalla maggior parte dei programmi relativi al testo. La lezione segue i seguenti passaggi:
-
Che cos’è un’espressione regolare.
-
I componenti principali di un’espressione regolare.
-
Le differenze tra espressioni regolari basiche ed estese.
-
Come eseguire semplici ricerche di testo e file utilizzando espressioni regolari.
Risposte agli Esercizi Guidati
-
Quale espressione regolare estesa corrisponderebbe a qualsiasi indirizzo email, come
info@example.org
?egrep "\S+@\S+\.\S+"
-
Quale espressione regolare estesa corrisponderebbe solo a qualsiasi indirizzo IPv4 nel formato standard a quattro punti, come
192.168.15.1
?egrep "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
-
Come può essere usato il comando
grep
per elencare il contenuto del file/etc/services
, scartando tutti i commenti (righe che iniziano con#
)?grep -v ^# /etc/services
-
Il file
domains.txt
contiene un elenco di nomi di dominio, uno per riga. Come sarebbe usato il comandoegrep
per elencare solo i domini.org
o.com
?egrep ".org$|.com$" domains.txt
Risposte agli Esercizi Esplorativi
-
Dalla directory corrente, in che modo il comando
find
userebbe un’espressione regolare estesa per cercare tutti i file che non contengono un suffisso di file standard (i nomi di file non terminano con.txt
o.c
, per esempio)?find . -type f -regextype egrep -not -regex '.*\.[[:alnum:]]{1,}$'
-
Il comando
less
è il paginatore predefinito per visualizzare file di testo lunghi nell’ambiente shell. Digitando/
è possibile inserire un’espressione regolare nel prompt di ricerca per passare alla prima corrispondenza trovata. Per rimanere nella posizione del documento corrente ed evidenziare solo le corrispondenze, quale combinazione di tasti deve essere inserita al prompt di ricerca?Premendo Ctrl+K prima di inserire l’espressione di ricerca.
-
In
less
, come sarebbe possibile filtrare l’output in modo che vengano visualizzate solo le righe che corrispondono a un’espressione regolare?Premendo & e inserendo l’espressione di ricerca.