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


11.2.7 Contare cose

Il programma di utilità wc (word count, contatore di parole) conta righe, parole, e caratteri in uno o più file in input. La sua sintassi è la seguente:

wc [-lwc] [file …]

Se nessun file è specificato sulla riga di comando, wc legge il suo standard input. Se ci sono più file, stampa anche il contatore totale di tutti i file. Le opzioni e il loro significato sono i seguenti:

-l

Conta solo le righe.

-w

Conta solo le parole. Una “parola” è una sequenza contigua di caratteri non bianchi, separata da spazi e/o TAB. Fortunatamente, questo è il modo normale in cui awk separa i campi nei suoi record in input.

-c

Conta solo i caratteri.

Implementare wc in awk è particolarmente elegante, perché awk fa molto lavoro al posto nostro; divide le righe in parole (cioè, campi) e le conta, conta le righe (cioè, i record), e può facilmente dire quanto è lunga una riga.

Questo programma usa la funzione di libreria getopt() (vedi la sezione Elaborare opzioni specificate sulla riga di comando) e le funzioni di passaggio da un file all’altro (vedi la sezione Trovare i limiti dei file-dati).

Questa versione ha una differenza significativa rispetto alle versioni tradizionali di wc: stampa sempre i contatori rispettando l’ordine righe, parole e caratteri. Le versioni tradizionali rilevano l’ordine in cui sono specificate le opzioni -l, -w e -c sulla riga di comando, e stampano i contatori in quell’ordine.

La regola BEGIN si occupa degli argomenti. La variabile stampa_totale è vera se più di un file è presente sulla riga di comando:

# wc.awk --- conta righe, parole, caratteri

# Opzioni:
#    -l    conta solo righe
#    -w    conta solo parole
#    -c    conta solo caratteri
#
# Il default è di contare righe, parole, caratteri
#
# Richiede le funzioni di libreria getopt()
# e il programma di libreria che gestisce
# il passaggio da un file dati al successivo

BEGIN {
    # consente a getopt() di stampare un messaggio se si specificano
    # opzioni non valide. Noi le ignoriamo
    while ((c = getopt(ARGC, ARGV, "lwc")) != -1) {
        if (c == "l")
            conta_righe = 1
        else if (c == "w")
            conta_parole = 1
        else if (c == "c")
            conta_caratteri = 1
    }
    for (i = 1; i < Optind; i++)
        ARGV[i] = ""

    # se nessuna opzione è specificata, conta tutto
    if (! conta_righe && ! conta_parole && ! conta_caratteri)
        conta_righe = conta_parole = conta_caratteri = 1

    stampa_totale = (ARGC - i > 1)
}

La funzione a_inizio_file() è semplice; si limita ad azzerare i contatori di righe, parole e caratteri, e salva il valore corrente di nome-file in nome_file:

function a_inizio_file(file)
{
    righe = parole = caratteri = 0
    nome_file = FILENAME
}

La funzione a_fine_file() aggiunge i numeri del file corrente al totale di righe, parole, e caratteri. Poi stampa i numeri relativi al file appena letto. La funzione a_inizio_file() azzera i numeri relativi al file-dati seguente:

function a_fine_file(file)
{
    totale_righe += righe
    totale_parole += parole
    totale_caratteri += caratteri
    if (conta_righe)
        printf "\t%d", righe
    if (conta_parole)
        printf "\t%d", parole
    if (conta_caratteri)
        printf "\t%d", caratteri
    printf "\t%s\n", nome_file
}

C’è una regola che viene eseguita per ogni riga. Aggiunge la lunghezza del record più uno, a caratteri.82 Aggiungere uno alla lunghezza del record è necessario, perché il carattere di ritorno a capo, che separa i record (il valore di RS) non è parte del record stesso, e quindi non è incluso nella sua lunghezza. Poi, righe è incrementata per ogni riga letta, e parole è incrementato con il valore NF, che è il numero di “parole” su questa riga:

# per ogni riga...
{
    caratteri += length($0) + 1    # aggiunge un ritorno a capo
    righe++
    parole += NF
}

Infine, la regola END si limita a stampare i totali per tutti i file:

END {
    if (stampa_totale) {
        if (conta_righe)
            printf "\t%d", totale_righe
        if (conta_parole)
            printf "\t%d", totale_parole
        if (conta_caratteri)
            printf "\t%d", totale_caratteri
        print "\ttotale"
    }
}

Note a piè di pagina

(82)

Poiché gawk gestisce le localizzazioni in cui un carattere può occupare più di un byte, questo codice conta i caratteri, non i byte.


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