Successivo: , Precedente: , Su: Cloni   [Contenuti][Indice]


11.2.2 Ricercare espressioni regolari nei file

Il programma di utilità egrep ricerca occorrenze di espressioni regolari all’interno di file. Usa espressioni regolari che sono quasi identiche a quelle disponibili in awk (vedi la sezione Espressioni regolari). Si richiama così:

egrep [opzioni] 'espressione' file

espressione è un’espressione regolare. Normalmente, l’espressione regolare è protetta da apici per impedire alla shell di espandere ogni carattere speciale come nome-file. Normalmente, egrep stampa le righe per cui è stata trovata una corrispondenza. Se nella riga di comando si richiede di operare su più di un nome-file, ogni riga in output è preceduta dal nome del file, e dal segno due punti (:).

Le opzioni di egrep sono le seguenti:

-c

Stampa un contatore delle righe che corrispondono al criterio di ricerca, e non le righe stesse.

-s

Funziona in silenzio. Non si produce alcun output ma il codice di ritorno indica se il criterio di ricerca ha trovato almeno una corrispondenza.

-v

Inverte il senso del test. egrep stampa le righe che non soddisfano il criterio di ricerca ed esce con successo se il criterio di ricerca non è soddisfatto.

-i

Ignora maiuscolo/minuscolo sia nel criterio di ricerca che nei dati in input.

-l

Stampa (elenca) solo i nomi dei file che corrispondono, e non le righe trovate.

-e espressione

Usa espressione come regexp da ricercare. Il motivo per cui è prevista l’opzione -e è di permettere dei criteri di ricerca che inizino con un ‘-’.

Questa versione usa la funzione di libreria getopt() (vedi la sezione Elaborare opzioni specificate sulla riga di comando) e il programma di libreria che gestisce il passaggio da un file dati al successivo (vedi la sezione Trovare i limiti dei file-dati).

Il programma inizia con un commento descrittivo e poi c’è una regola BEGIN che elabora gli argomenti della riga di comando usando getopt(). L’opzione -i (ignora maiuscolo/minuscolo) è particolarmente facile da implementare con gawk; basta usare la variabile predefinita IGNORECASE (vedi la sezione Variabili predefinite):

# egrep.awk --- simula egrep in awk
#
# Opzioni:
#    -c    conta le righe trovate
#    -s    silenziosa: genera solo il codice di ritorno
#    -v    inverte test, successo se regexp non presente
#    -i    ignora maiuscolo/minuscolo
#    -l    stampa solo nomi file
#    -e    espressione da ricercare
#
# Richiede la funzione getopt() e il programma di libreria
#   che gestisce il passaggio da un file dati al successivo

BEGIN {
    while ((c = getopt(ARGC, ARGV, "ce:svil")) != -1) {
        if (c == "c")
            conta_e_basta++
        else if (c == "s")
            non_stampare++
        else if (c == "v")
            inverti_test++
        else if (c == "i")
            IGNORECASE = 1
        else if (c == "l")
            solo_nomi_file++
        else if (c == "e")
            criterio_di_ricerca = Optarg
        else
            sintassi()
    }

Nel seguito c’è il codice che gestisce il comportamento specifico di egrep. Se non è fornito esplicitamente alcun criterio di ricerca tramite l’opzione -e, si usa il primo argomento sulla riga di comando che non sia un’opzione. Gli argomenti della riga di comando di awk fino ad ARGV[Optind] vengono cancellati, in modo che awk non tenti di elaborarli come file. Se non è stato specificato alcun nome di file, si usa lo standard input, e se è presente più di un nome di file, lo si annota, in modo che i nomi-file vengano scritti prima di ogni riga di output corrispondente:

    if (criterio_di_ricerca == "")
        criterio_di_ricerca = ARGV[Optind++]

    for (i = 1; i < Optind; i++)
        ARGV[i] = ""
    if (Optind >= ARGC) {
        ARGV[1] = "-"
        ARGC = 2
    } else if (ARGC - Optind > 1)
        servono_nomi_file++

#    if (IGNORECASE)
#        criterio_di_ricerca = tolower(criterio_di_ricerca)
}

Le ultime due righe sono solo dei commenti, in quanto non necessarie in gawk. Per altre versioni di awk, potrebbe essere necessario utilizzarle come istruzioni effettive (togliendo il "#").

Il prossimo insieme di righe dovrebbe essere decommentato se non si sta usando gawk. Questa regola converte in minuscolo tutti i caratteri della riga in input, se è stata specificata l’opzione -i.80 La regola è commentata perché non è necessaria se si usa gawk:

#{
#    if (IGNORECASE)
#        $0 = tolower($0)
#}

La funzione a_inizio_file() è chiamata dalla regola in ftrans.awk quando ogni nuovo file viene elaborato. In questo caso, non c’è molto da fare; ci si limita a inizializzare una variabile contatore_file a zero. contatore_file serve a ricordare quante righe nel file corrente corrispondono al criterio di ricerca. Scegliere come nome di parametro da_buttare indica che sappiamo che a_inizio_file() è chiamata con un parametro, ma che noi non siamo interessati al suo valore:

function a_inizio_file(da_buttare)
{
    contatore_file = 0
}

La funzione endfile() viene chiamata dopo l’elaborazione di ogni file. Ha influenza sull’output solo quando l’utente desidera un contatore del numero di righe che sono state individuate. non_stampare è vero nel caso si desideri solo il codice di ritorno. conta_e_basta è vero se si desiderano solo i contatori delle righe trovate. egrep quindi stampa i contatori solo se sia la stampa che il conteggio delle righe sono stati abilitati. Il formato di output deve tenere conto del numero di file sui quali si opera. Per finire, contatore_file è aggiunto a totale, in modo da stabilire qual è il numero totale di righe che ha soddisfatto il criterio di ricerca:

function endfile(file)
{
    if (! non_stampare && conta_e_basta) {
        if (servono_nomi_file)
            print file ":" contatore_file
        else
            print contatore_file
    }

    totale += contatore_file
}

Si potrebbero usare i criteri di ricerca speciali BEGINFILE ed ENDFILE (vedi la sezione I criteri di ricerca speciali BEGINFILE ed ENDFILE), ma in quel caso il programma funzionerebbe solo usando gawk. Inoltre, questo esempio è stato scritto prima che a gawk venissero aggiunti i criteri speciali BEGINFILE ed ENDFILE.

La regola seguente fa il grosso del lavoro per trovare righe corrispondenti al criterio di ricerca fornito. La variabile corrisponde è vera se la riga è individuata dal criterio di ricerca. Se l’utente chiede invece le righe che non corrispondono, il senso di corrisponde è invertito, usando l’operatore ‘!’. contatore_file è incrementato con il valore di corrisponde, che vale uno o zero, a seconda che la corrispondenza sia stata trovata oppure no. Se la riga non corrisponde, l’istruzione next passa ad esaminare il record successivo.

Vengono effettuati anche altri controlli, ma soltanto se non si sceglie di contare le righe. Prima di tutto, se l’utente desidera solo il codice di ritorno (non_stampare è vero), è sufficiente sapere che una riga nel file corrisponde, e si può passare al file successivo usando nextfile. Analogamente, se stiamo solo stampando nomi-file, possiamo stampare il nome-file, e quindi saltare al file successivo con nextfile. Infine, ogni riga viene stampata, preceduta, se necessario, dal nome-file e dai due punti (:):

{
    corrisponde = ($0 ~ criterio_di_ricerca)
    if (inverti_test)
        corrisponde = ! corrisponde

    contatore_file += corrisponde    # 1 o 0

    if (! corrisponde)
        next

    if (! conta_e_basta) {
        if (non_stampare)
            nextfile

        if (solo_nomi_file) {
            print nome_file
            nextfile
        }

        if (servono_nomi_file)
            print nome_file ":" $0
        else
            print
    }
}

La regola END serve a produrre il codice di ritorno corretto. Se non ci sono corrispondenze, il codice di ritorno è uno; altrimenti, è zero:

END {
    exit (totale == 0)
}

La funzione sintassi() stampa un messaggio per l’utente, nel caso siano state specificate opzioni non valide, e quindi esce:

function sintassi()
{
    print("sintassi: egrep [-csvil] [-e criterio_di_ricerca] [file ...]")\
    	> "/dev/stderr"
    print("\n\tegrep [-csvil] criterio_di_ricerca [file ...]") > "/dev/stderr"
    exit 1
}

Note a piè di pagina

(80)

Inoltre, qui si introduce un errore subdolo; se una corrispondenza viene trovata, viene inviata in output la riga tradotta, non quella originale.


Successivo: , Precedente: , Su: Cloni   [Contenuti][Indice]