Precedente: Programma uniq, Su: Cloni [Contenuti][Indice]
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:
-lConta solo le righe.
-wConta 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.
-cConta 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"
}
}
Poiché gawk gestisce le
localizzazioni in cui un carattere può occupare più di un byte, questo codice
conta i caratteri, non i byte.
Precedente: Programma uniq, Su: Cloni [Contenuti][Indice]