Zakładając, że wiersze miałyby być oddzielone pustymi liniami to
skrypt mógłby wyglądać tak:
#!/usr/bin/env bash
c() {
awk 'BEGIN {l=0; w=0} m=/^[[:blank:]]*$/ {if (l) print w; l=0; w=0} !m {l++; w+=NF} END {if (l) print w}' "${1:-/dev/stdin}" 2>/dev/null
}
if [[ "$#" -gt 0 ]]; then
for arg; do
[[ -r "$arg" ]] || continue
c "$arg"
done
else
c
fi
Chyba nie muszę szczegółowo tłumaczyć głównej konstrukcji. Jeśli podane są jakieś argumenty to skrypt traktuje je jako nazwy plików do sprawdzenia a w przeciwnym wypadku czyta dane ze standardowego wejścia.
Pokrótce omówię zagnieżdżony skrypt AWK.
Przed przetwarzaniem kolejnych linii dokonujemy inicjalizacji licznika linii (
l) oraz licznika słów (
w).
m=/^[[:blank:]]*$/ {if (l) print w; l=0; w=0} !m {l++; w+=NF}
Jeśli aktualnie analizowana linia jest pusta (podany wzorzec uwzględnia linie zawierające co najwyżej same białe znaki) to wypisujemy stan licznika
w jeśli licznik
l on różny od zera. Musimy także pamiętać o ich wyzerowaniu.
W przeciwnym wypadku (gdy linia nie pasuje do wzorca
m, czyli zawiera tekst) inkrementujemy licznik
l oraz zwiększamy licznik
w o liczbę słów w linii (
NF oznacza liczbę pól).
Na koniec (po przejrzeniu wszystkich linii) wypisujemy wartość licznika
w jeśli wartość licznika
l jest niezerowa. Jest to potrzebne ze względu na to, że dane mogą kończyć się niepustą linią a bez tego ostatni "wierszyk" nie zostałby uwzględniony.