grep

Da Wikipedia, l'enciclopedia libera.

grep (general regular expression print) è un comando dei sistemi Unix e Unix-like, e più in generale dei sistemi POSIX[1] e GNU[2], che ricerca in uno o più file di testo le linee che corrispondono ad uno o più modelli specificati con espressioni regolari o stringhe letterali, e produce un elenco delle linee (o anche dei soli nomi di file) per cui è stata trovata corrispondenza. È un tipo di filtro.

grep è comunemente utilizzato per ricercare le occorrenze di una o più parole in una serie di file, spesso in congiunzione con i comandi find e xargs tramite una pipeline software.

grep può generalmente essere impiegato anche con file binari, ad esempio per ricercare la presenza di particolari etichette Exif all'interno di file contenenti immagini digitali. In particolare, la versione GNU di grep in questo caso elenca i nomi dei file contenenti la stringa o espressione regolare indicata (e non anche la porzione di testo corrispondente, come normalmente accade per i file di testo).

Uso[modifica | modifica wikitesto]

La sintassi generale di grep è:

grep [opzioni] [-e] modello1 [-e modello2 …] [--] [file1 [file2 …] ]

I parametri facoltativi file indicano i nomi dei file su cui effettuare la ricerca. Se non specificati, la ricerca viene effettuata sui dati letti dallo standard input. Specificando più di un parametro file, ogni linea per cui è stata trovata una corrispondenza viene preceduta dal nome del file che la contiene e dal suo numero di linea; in caso di un solo parametro file (o nessuno) viene invece indicato solo il contenuto della linea stessa.

I parametri modello specificano il criterio di ricerca, ed il comportamento predefinito prevede che si tratti di espressioni regolari. Una linea trova corrispondenza se soddisfa almeno uno dei modelli.

Il doppio trattino -- (facoltativo) indica che i parametri successivi non sono da considerarsi opzioni.

Tra le opzioni principali vi sono:

-i
Ignora le differenze tra lettere maiuscole e minuscole.
-n
Precede ogni linea dei risultati con il numero di linea all'interno del file (partendo da 1).
-l
Indica solo i nomi dei file in cui è stata trovata almeno una corrispondenza (ciascun file è elencato una sola volta, indipendentemente dal numero di corrispondenze in esso trovate).
-v
Nega i modelli specificati, producendo un elenco delle linee che non soddisfano alcun modello.
-E
I modelli sono espressioni regolari estese invece che espressioni regolari di base.
-F
I modelli sono stringhe che vanno ricercate in maniera letterale.
-c
Produce per ciascun file solo il conteggio del numero di linee che corrispondono.

La versione GNU di grep (disponibile ad esempio sui sistemi GNU/Linux) supporta tra le altre anche le seguenti opzioni:

-numero
Ogni linea per cui è stata trovata una corrispondenza viene elencata insieme al numero specificato di linee ad essa adiacenti (per fornire il contesto). Ogni linea è elencata una sola volta, per cui anche se vi fossero corrispondenze nelle linee adiacenti, esse non saranno ripetute.
-A numero
Fa seguire ogni linea per cui è stata trovata una corrispondenza dal numero specificato di linee che la seguono (la "A" sta per after - dopo).
-B numero
Fa precedere ogni linea per cui è stata trovata una corrispondenza dal numero specificato di linee che la precedono (la "B" sta per before - prima).

Varianti[modifica | modifica wikitesto]

Storicamente esistono anche varianti di grep chiamate egrep e fgrep, le quali interpretano i modelli rispettivamente come espressioni regolari estese e come stringhe letterali.

L'uso delle opzioni -E e -F equivale all'uso di queste varianti.

Origine del nome grep[modifica | modifica wikitesto]

Il nome del programma deriva dal comando g/re/p dell'editor di testo ed che svolge una funzione simile, ovvero ricercare globalmente (ovvero in tutto il file e non in una sola linea) una espressione regolare (regular expression) e di mostrare (print) le corrispondenze.

Punti di attenzione[modifica | modifica wikitesto]

Ancoraggio del testo da ricercare[modifica | modifica wikitesto]

Un'espressione regolare che sia priva di ancoraggi può trovare corrispondenza in un punto qualsiasi della linea, e quindi anche nel mezzo di una parola. Questo può essere fonte di risultati inattesi se quello che si intendeva ricercare era in realtà un'intera parola. Ad esempio l'espressione regolare "10" trova corrispondenza anche in "100", "101", "320103" e così via.

Soluzione con GNU grep[modifica | modifica wikitesto]

La versione GNU di grep, oltre che per gli ancoraggi a inizio e fine linea, ha supporto anche per particolari metacaratteri che rappresentano l'inizio e/o la fine di una qualsiasi parola, e possono essere usati per ancorare il resto dell'espressione regolare. Nello specifico la sequenza \< corrisponde al punto d'inizio di una parola, \> al punto in cui termina una parola, e \b al punto d'inizio o di termine di una parola. Ad esempio, l'espressione regolare \<10\> trova corrispondenza solo in linee che contengono "10" come parola a sé stante, in maniera visivamente isolata, e non "100" o "210".

Soluzione con espressioni regolari POSIX[modifica | modifica wikitesto]

Gli ancoraggi previsti dallo standard POSIX sono solo quelli che rappresentano l'inizio e la fine della linea, rispettivamente l'accento circonflesso ^ ed il simbolo del dollaro $; in questo caso un possibile rimedio consiste nell'estendere l'espressione regolare circondandola con [^[:alnum:]], ad esempio con [^[:alnum:]]10[^[:alnum:]]; ciò tuttavia non copre i casi in cui vi sia corrispondenza all'inizio o alla fine della linea (in cui non vi sono caratteri precedenti o caratteri successivi) e nemmeno il caso in cui l'espressione sia l'intera linea. Per considerare anche queste situazioni occorre espandere manualmente i quattro casi, ricorrendo a più opzioni -e. Ad esempio la riga di comando di grep diventerebbe:

grep -e "[^[:alnum:]]10[^[:alnum:]]" -e "[^[:alnum:]]10$" -e "^10[^[:alnum:]]" -e "^10$" …

Oppure si può anche ricorrere alle espressioni regolari estese (opzione di grep -E) e al metacarattere | per indicare più espressioni alternative, ad esempio:

 grep -E "[^[:alnum:]]10[^[:alnum:]]|[^[:alnum:]]10$|^10[^[:alnum:]]|^10$" …

Stringhe letterali cercate come espressioni regolari[modifica | modifica wikitesto]

Il comportamento predefinito di grep prevede che i modelli usati per la ricerca siano delle espressioni regolari e non stringhe letterali (per le quali occorre specificare l'apposita opzione -F), ma è facile scordarsi della distinzione poiché non capita spesso di dover ricercare testo contenente dei metacaratteri come il punto ..

Il problema è che la distinzione in realtà sussiste, e che spesso le stringhe contenenti dei metacaratteri (come ad esempio un indirizzo IP numerico 10.10.1.1) sono anche delle valide espressioni regolari, per cui grep non segnala alcun errore, ma può fornire risultati del tutto inattesi. Ad esempio l'espressione regolare 10.1.1.1 trova corrispondenza anche in 10.101.1 o in 1091a1b1 o altro ancora, e unitamente al fatto che non sia ancorata aumenta la possibilità di risultati inattesi.

Una possibile soluzione consiste appunto nell'usare l'opzione -F in modo da effettuare ricerche letterali; ciò tuttavia impedisce di ancorare il testo (si ricorda che la stringa letterale 10.1.1.1 trova corrispondenza anche in 10.1.1.100 o anche 210.1.1.1).

Se ciò fosse un problema, occorre ricorrere ancora una volta alle espressioni regolari, indicando che i metacaratteri vanno considerati in maniera letterale prefissandoli uno ad uno con la barra inversa \ e poi procedendo come per il caso in cui si necessita di ancoraggio. Ad esempio, con la versione GNU di grep:

grep -e '\<10\.1\.1\.1\>' …

Utilizzo della barra inversa[modifica | modifica wikitesto]

Le shell testuali dei sistemi Unix e Unix-like effettuano sostituzioni sull'intera riga di comando prima di eseguirla, tra le quali vi è anche quella delle sequenze di caratteri che iniziano con una barra inversa \ quando non sono specificate tra virgolette doppie o apici singoli. Ad esempio, la riga di comando

grep -e 10\.1\.1\.1

viene trasformata dalla shell in

grep -e 10.1.1.1

e quindi grep si ritroverebbe ad operare ricerche con l'espressione regolare 10.1.1.1, che probabilmente non era nelle intenzioni originali.

È quindi opportuno specificare le espressioni regolari tra virgolette doppie o apici singoli, come ad esempio in

grep -e '10\.1\.1\.1'

Utilizzo con find[modifica | modifica wikitesto]

Per effettuare ricerche in più file all'interno di una gerarchia di directory si usa spesso grep in combinazione con il comando find, ad esempio con:

find . -type f -name "*.c" -exec grep -e "espressione" {} +

Così facendo esiste tuttavia la possibilità che grep sia invocato da find con un unico file da esaminare (ad esempio se find trovasse un solo file), nel qual caso grep procede a elencare le linee corrispondenti senza prefissarle con il nome file a cui esse appartengono (che è il comportamento predefinito nel caso di un unico file), quindi offrendo un risultato diverso da quello normalmente atteso.

Per rimediare si può esplicitare direttamente tra i parametri di grep il nome di un primo file, in modo che grep sia invocato sempre con almeno due nomi di file da esaminare. Allo scopo torna comodo /dev/null, che è sempre presente e non contiene mai dati, ed è quindi l'ideale come file "riempitivo" che non influenza le ricerche. Ad esempio:

find . -type f -name "*.c" -exec grep -e "espressione" /dev/null {} +

Note[modifica | modifica wikitesto]

  1. ^ (EN) grep in The Open Group Base Specifications Issue 6 IEEE Std 1003.1-2008. URL consultato il 26 giugno 2009.
  2. ^ (EN) grep, print lines matching a pattern in GNU grep manual. URL consultato il 19 maggio 2008.

Collegamenti esterni[modifica | modifica wikitesto]

informatica Portale Informatica: accedi alle voci di Wikipedia che trattano di informatica