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:
-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" } }
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]