AWK kalba - sena ir nuolat aktuali

Antra dalis >>>>> subtiliau ir daugiau            

Pravartu paskaityti apie programavimo kompiuteriams palyginimą su kitais realaus gyvenimo aprašais > >>> >

Pradinė awk kalba buvo labai paprastutė ir orientuota į tekstinės informacijos srauto apdorojimą. Ji pasirodė apie 1977-uosius su Version 7 UNIX sistema. Vartotojams ji patiko ir jie ėmė ją naudoti savo reikmėms. Jos autoriai buvo Alfred V. Aho, Peter J. Weinberger ir Brian W. Kernighan (jų pavardžių pirmosios raidės ir sudarė awk pavadinimą) iš „AT&T Bell Labs“. Kalbos pavadinimo tarimas panašus į „auk“, reiškiančio „alką“ (paukštis), kuri tapo awk kalbos emblema. 1985 m. awk kalbos autoriai pamatė, kad kalba naudojama rimtesniems darbams nei jie buvo Effective AWK Programming numatę, todėl jie nusprendė ją išplėsti. Nauja versija šviesą išvydo 1987-ais ir ją vis dar galima sutikti SunOS 4.1.x versijose. awk kalbos galia, glaustumas, bet kartu ir ribotumas įkvėpė Larry Wall sukurti „Perl“ kalbą.

1989 m., išleista su “System V Release 4” awk kalba buvo vėl truputį išplėsta. Ši awk versija tapo pagrindu POSIX standartui.
Čia aprašysime bendrąsias awk savybes (pagal POSIX standartą). Įvairias awk realizacijas rasite Unix/Linux sistemose, o taip pat galite atsisiųsti nemokamas versijas „Windows“ (32 bitų) terpei: GAWK ir MAWK.

Labas, pasauli!

Įvadą į awk kalbą padarysime trimis būdais realizuodami „Labas, pasauli!” programą. Pradžioje pateiksime pagrindinius susitarimus, kuriuos naudosiu savo pavyzdžiuose: a) programas saugosiu failuose, kurių plėtinys bus .awk, pvz., hello.awk; apdorojamą tekstą įrašysiu į failą test.txt.

1. Panaudojant BEGIN šabloną – programa pradeda darbą, pateikia pranešimą ir baigia darbą. Į hello.awk įrašome tokią programą:

BEGIN { print “Labas, pasauli!” }

Ją įvykdome ir gauname atsakymą:
awk –f hello.awk
Labas, pasauli!

awk kalba ima duomenis iš įvedimo srauto (pvz., failo ar klaviatūros) ir rezultatus rašo į išvedimo srautą (pvz., ekraną). BEGIN šablonas nurodo veiksmus, kuriuos reikia atlikti prieš skaitant įvedimo srautą. Jei programoje tėra tik BEGIN šablonas (kaip ir yra mūsų pavyzdyje), neskaitomi jokie įvedimo srautai.

2. Apdorojant failą (test.txt), kuriame yra viena vienintelė (bet kokia) eilutė. Į hello.awk įrašome tokią programą:

{ print “Labas, pasauli!” }

Sukuriame test.txt failą:
echo Bet koks tekstas > test.txt

Vykdome programą ir gauname atsakymą:
awk –f hello.awk test.txt
Labas, pasauli!

Ši programa nuo ankstesnės tesiskiria tik tuo, kad nėra nurodytas BEGIN šablonas, o ją iškviečiant nurodytas failas test.txt. Programa skaito kiekvieną šio failo eilutę ir kiekvienai jų išveda pranešimą. Kadangi faile tėra viena eilutė, tai pranešimas pateikiamas tik vieną kartą.

3. Apdorojant failą (test.txt), kuriame (tarp kitų kelių) yra viena eilutė, kurios tekstas yra „Labas, pasauli!”. Sukuriame tokį test.txt failą:

Bet koks tekstas
Labas, pasauli!
Bet koks tekstas

Į hello.awk įrašome tokią programą:
/ Labas, pasauli!/ { print }

Vykdome programą ir gauname atsakymą:
awk –f hello.awk test.txt
Labas, pasauli!

Ši programa skaito po vieną eilutę iš failo test.txt ir ją lygina su nurodytu šablonu (kuris nurodytas tarp pasvirų brūkšnių / ... / ). Jei eilutė sutampa, atspausdinama visa toji eilutė (nes print sakinys yra be parametrų).

Galite paeksperimentuoti, kad pajustumėte, kaip awk yra valdoma įvedimo srauto. Antrą ir trečią pavyzdžius iškvieskite nenurodydami jokio failo, t.y. vykdykite
awk –f hello.awk

Šiuo atveju programos lauks įvedimo iš klaviatūros. Jūs galite įvesti eilutę po eilutės (gale paspausdami ENTER klavišą). Po paskutinės eilutės turite nurodyti duomenų srauto pabaigą (daugelyje sistemų tai Ctrl- D arba Ctrl-Z, po kurio gali tekti paspausti ir ENTER klavišą).

4. Atspausdinti failą. O dabar sukuriame failą spausdink.awk:
{print}

Panaudojame test.txt iš ankstesnio pavyzdžio ir vykdome gaudami atsakymą:
awk -f spausdink.awk test.txt
Bet koks tekstas
Labas, pasauli!
Bet koks tekstas

Kadangi nenurodytas šablonas, kaip ankstesniame pavyzdyje, tai laikoma, kad kiekviena nuskaityta eilutė tenkina šabloną, todėl ir atspausdinama.

AWK kalbos modelis

awk programą sudaro vadinamasis nuolatinis įvedimo ciklas - tai procedūra, be paliovos kartojama tol, kol patenkinama tam tikra sąlyga, nutraukianti ciklo kartojimą. Šio ciklo programuoti nereikia – jis užtikrinamas automatiškai. Tai tarsi terpė, kurioje vykdomas programos kodas. Kodas rašomas tik kiekvienos veiksnios eilutės apdorojimui. Love AWK cup awk kalba sudaryta iš sąrašo, kurį sudaro šablono-veiksmų poros, kurių formatas:
šablonas { veiksmai } šablonas { veiksmai }

awk numatė ir du specialius (šablonų) atvejus – tai BEGIN ir END, nurodantys, kad reikia atlikti veiksmus a) prieš pradedant įvedimo ciklą; b) užbaigus įvedimo ciklą. BEGIN jau buvo panaudotas mūsų pateiktame pavyzdyje.

awk veikia eilučių tikrinimo su šablonu principu. Kai nuskaitoma eilutė, ji sulyginama su nurodytu šablonu ir, jei šablonas yra tenkinamas, vykdomi nurodyti veiksmai (jei nėra nurodyti jokie veiksmai, eilutė tiesiog „spausdinama“). Šablonai užrašomi kaip reguliariosios išraiškos. Čia mes išsamiai neaprašinėsime jų - jų aprašymus teks susirasti kitur.

Veiksmams galima naudoti kintamuosius, aritmetinius skaičiavimus, funkcijas. awk pateikia didelį kiekį funkcijų, o kai kurios realizacijos leidžia jų kiekį išplėsti sukompiliuotomis bibliotekomis. Pateiksime pavyzdį, iliustruojantį aprašytas koncepcijas. Šiame pavyzdyje bus paskaičiuojamos įvedimo sraute esančios tuščios eilutės. Joje naudojamas šablonas ^$, nurodantis tuščią eilutę (pasviri brūkšniai nurodo šablono sritį). Programose naudingi komentarai, kurie prasideda diezo (#) ženklu.

Į failą blank.awk įrašykite:

# Ši awk programa suskaičiuos tuščias eilutes įvedimo sraute
BEGIN { t = 0; print "Skaičiuojamas tuščių eilučių kiekis" }
/^$/ { t = t + 1 }
END { print "Tuščios eilutes:", t }

Tada vykdykite, nurodydami parengtą failą test.txt:
awk –f hello.awk test.txt

Be to, eilutė laikoma sudaryta iš laukų, kuriuos atskiria tam tikras skirtukas (nutylint – „tuščia vieta“, t.y., tarpas, tabuliacijos kodas ir pan.). Skirtuko reikšmė nurodoma specialiu kintamuoju FS. Laukai nurodomi $1, $2, ... Specialus žymuo $0 reiškia visą eilutę.

Tarkim, turime tokį failą kiekiai.txt:

ID    Vardas Pavarde     Kiekis
ID111 Jonas  Jonaitis    500
ID222 Petras Petraitis   700

Parašome programą visikiekiai.awk, skirtą pirmo ir ketvirto laukų pateikimui:
{print $1 $4}

Vykdome ir gauname atsakymą:

awk -f visikiekiai.awk kiekiai.txt
ID111500
ID222700

Hm, nepatiko?! Tada modifikuojame programą nurodydami, kad laukai atskiriami:
{print $1 $4}

Vykdome ir gauname kitokį atsakymą:

awk -f visikiekiai.awk kiekiai.txt
ID Kiekis
ID111 500
ID222 700

Yra keletas specialių kintamųjų:
NR - eilučių kiekis įvedimo sraute;
NF - laukų kiekis veiksnioje eilutėje (paskutinis laukas eilutėje žymimas $NF);
FILENAME - įvedimos srauto (failo) vardas;
FS - laukų skirtukas;
RS - eilučių skirtukas (nutylint – naujos eilutės kodas);
OFS - laukų skirtukas išvedimo sraute („spausdinant“ laukus);
ORS - eilučių skirtukas išvedimo sraute („spausdinant“);
OFMT - išvedamo skaičiaus formatas (nutylint „%.6g“).;
ir kt.

Pastaba: šie „žaidimai“ patikrinti su Fedora, tačiau mawk ir gawk jie neveikia.

NR kintamojo panaudojimo pavyzdžiai. Sukuriame failą text.txt:

Pirma
Antra
Trecia
Ketvirta
Penkta

Šis pavyzdys išves tik antrąją eilutę:
awk 'NR==2 {print $0}' text.txt
Antra

Jei norime pateikti eilučių intervalą, nurodome taip:

awk 'NR==2,NR==4 {print $0}' text.txt
Antra
Trecia
Ketvirta

Ir pagaliau, jei norime išvesti ne intervalą, o konkrečias eilutes, atskiriame kabliataškiu:

awk 'NR==2;NR==4 {print $0}' text.txt
Antra
Ketvirta

Panašiai galime nurodyti ir šabloną konkrečiam laukui - trečiame lauke ieskoti tis:
awk '$3~/tis/ {print $2,$3}' a.txt
Jonas Jonaitis 500
Petras Petraitis 700

Pateiksime dar vieną awk programos pavyzdį:
# Suskaičiuoti eilutes, žodžius ir simbolius, esančius įvedimo sraute
function sumuoti (p1, p2) { return p1 + p2 }
BEGIN { nw = 0; ns = 0 }
{ nw += NF; ns = sumuoti(ns, length + 1) }
END { print "Tekste yra", NR, "eilučių,", nw, "žodžių ir", ns, "simbolių" }

Šiame pavyzdyje panaudojome savą funkciją „sumuoti“, kuri sudeda du skaičius, nurodytus kaip parametrai. nw += NF užrašymas yra nw = nw + NF trumpinys (analogiškai operatoriams C++ bei java kalbose). length yra funkcija, gražinanti simbolių eilutės ilgį. Jei parametras nenurodytas, naudojama $0 reikšmė (t.y., visa veiksni eilutė). Taigi, išraiška length + 1 yra tapati length($0) + 1. Nėra nurodytas joks šablonas, tad apdorojamos visos įvedimo srauto eilutės.

Laukų skirtuku gali būti ne vien tik vienas simbolis. Jei FS kintamajam priskirti keli simboliai, jie interpretuojami kaip reguliarioji išraiška. Pvz.,
FS = “[:;\t]”
laukų skirtukais laikys bet kurį iš nurodytų trijų simbolių (dvitaškį, kabliataškį ir tabuliacijos kodą).

Nuorodoje į lauką galima panaudoti bet kokią išraišką ar kintamąjį, pvz.,
BEGIN { f = 2 }
{ print $f, $(f+2) }

Atspausdinami failo kiekvienos eilutės antrasis ir ketvirtasis laukai.

Galima tikrinti, ar šabloną atitinka tik kuris nors vienas laukas. Tam skirtas operatorius „~“ (tildė). Jam priešingas operatorius (t.y., neatitinka šablono) yra „!~”. Tai pailiustruosime pavyzdžiu. Laikysime, kad duomenų failas yra prekių sąrašas ir yra tokios struktūros:
- laukai skiriami „;“ (kabliataškiais;
- pirmas laukas nurodo lauko numerį, kuriame yra prekių kiekis;
- prekės pavadinimas yra iškart kitas laukas po kiekio.

Failo (test.txt) pavyzdys:
3;PR43561;12;Stiklo lapai;Kita informacija
Laikomatis;PR123456; Nepaskaičiuota
4;PR00033;Dėžėse po 3;8;Stebulės:Raudonos

Programa išves prekių pavadinimus ir jų kiekį, o taip pat paskaičiuos bendrą prekių kiekį. Papildomai, ji patikrina, ar pirmas laukas yra skaitmeninis ir, jei jis nėra skaitmeninis, išveda šio pirmojo lauko reikšmę. Panaudojamas ir išvedimo srauto laukų skirtuko kintamasis OFS.

# fld.awk - nurodyto lauko sumavimas
BEGIN { FS = ";"; OFS = ": "; kiekis = 0 }
$1 ~ /[0-9]+/ { print $($1+1), $($1); kiekis += $($1) }
$1 !~ /[0-9]+/ { print "Nenurodyta" $1 }
END { print "Viso", kiekis }

Vykdome programą:
awk –f fld.awk test.txt
Stiklo lapai: 12
Nenurodyta: Laikomatis
Stebulės: 8
Viso: 20

Įrašai apimantys kelias eilutes. Galima apdoroti duomenis, kai įrašą sudaro kelios eilutės. Tarkim, kad įrašus sudaro po dvi eilutes, kuriuos skiria tuščia eilutė. Šis pavyzdys atspausdina įrašus juos sujungiant į vieną eilutę:
BEGIN { FS = "\n"; RS = ""; }
{ print $1, $NF; }


Manome, kad šito pradiniam susipažinimui su awk kalba pakanka. Ateityje planuojami papildomi puslapiai, skirti šiai kalbai. Visi pavyzdžiai buvo išbandyti su GAWK ir MAWK realizacijomis Windows terpei (nuorodos - atsisiuntimui).

Antra dalis >>>>> subtiliau ir daugiau             

Ankstesnės "Advanced HTML" skyrelio temos:
Tcl kalba
ASP patarimų liūnas
Unix komandinės eilutė
AWK kalba - subtiliau ir daugiau
Dygios JavaScript eilutės
Sveikųjų skaičių žaidimai
JavaScript atspindžiai
Didžiųjų duomenų mitas
Pelė uodega švystelėjo...
CGI.pm biblioteka: sausainiai
Ką delne mums neša HTML 4.0?
Lambda išraiškos – Java į naują lygį
Kaip valdyti piešinių pakrovimo tvarką
Kaip lankytoją nukreipti į kitą WWW puslapį
Kaip sužinoti ekrano charakteristikas?
Vaizdi rašysena - VB Script
Programavimas Unix aplinkoje
Programavimo kalbų istorija
Papildytoji tikrovė
Ruby on Rails
Kompiuterių ištakos
Ateities kalbos?
Kobolo motina

JavaScript pradmenys
Programavimo kalbų klegesys
Nutylimųjų savybių ieškant
Viešojo rakto kriptografija
Tiesiog - Java
Vartiklis