YAzyk obrabotki strukturirovannyh tekstov AWK
Proizvodstvenno-vnedrencheskij kooperativ
"I N T E R F E J S"
Dialogovaya Edinaya Mobil'naya
Operacionnaya Sistema
Demos/P 2.1
YAzyk obrabotki strukturirovannyh tekstov AWK
Moskva
1988
Annotaciya
YAzyk AWK ispol'zuetsya dlya kombinirovannoj obrabotki
simvol'nyh i chislovyh polej v zapisyah. V rezul'tate generi-
ruetsya otchet v zaplanirovannoj programmistom forme. Prog-
rammy na yazyke AWK mozhno effektivno ispol'zovat' kak fil'try
dannyh dlya preobrazovaniya vyvoda odnoj programmy i peredachi
rezul'tata fil'tracii na vhod drugoj. V sisteme DEMOS usta-
novlen interpretator yazyka AWK, kotoryj poluchil nazvanie
awk.
1. Principy raboty interpretatora awk
Lyuboj tekst imeet nekotoruyu strukturu, v prostejshem
sluchae ee elementami yavlyayutsya stroki i slova teksta. V
yazyke AWK tekst rassmatrivaetsya kak spisok zapisej i polej v
nih i na etoj osnove vypolnyaetsya nekotoryj opredelennyj
programmistom algoritm obrabotki. Dopustim, imeetsya sleduyu-
shchij tekst:
Sidorov Sidor Sidorovich 1957 g.r. 220 rub sl.
Petrov Petr Ivanovich 1962 g.r. 200 rub sl.
Ivanov Mihail Konstantinovich 1965 g.r. 180 rub rab.
Volkov Leonid Nikolaevich 1950 g.r. 280 rub rab.
Semenov Petr Mihajlovich 1958 g.r. 210 rub rab.
|tot tekst strukturirovan: zapisi - eto stroki, polya v stro-
kah - slova i chisla. V kazhdoj zapisi soderzhitsya po 8 polej,
razdelyayushchihsya probelami. Znachashchim (v kachestve razdelitelya)
yavlyaetsya tol'ko odin probel mezhdu polyami, ostal'nye ignori-
ruyutsya. Rassmotrim neskol'ko prostyh programm na yazyke AWK.
Primer 1. AWK-programma vyvodit pervye tri polya iz
vos'mi, poryadok polej v vyvode izmenen i pered kazhdoj stro-
koj pechataetsya simvol tabulyacii
{ print( "\t", $2, $3, $1 ); }
Operator print vypolnyaetsya dlya vseh vhodnyh zapisej. Posle
vypolneniya programmy poluchim:
Sidor Sidorovich Sidorov
Petr Ivanovich Petrov
Mihail Konstantinovich Ivanov
Leonid Nikolaevich Volkov
Vladimir Mihajlovich Semenov
Kak vidno iz programmy, znacheniya polej podstavlyayutsya sleduyu-
shchim obrazom:
$nomer_polya_v_zapisi
Pervomu polyu sootvetstvuet 1. V obshchem sluchae nomerom polya
mozhet byt' znachenie vyrazheniya. Znacheniem podstanovki $0
yavlyaetsya vsya zapis'.
Primer 2. AWK-programma vyvodit nomera strok posle
tabulyacii
{ print( "\t", NR, $2, $3, $1 ); }
Posle vypolneniya programmy poluchim:
- 3 -
1 Sidor Sidorovich Sidorov
2 Petr Ivanovich Petrov
3 Mihail Konstantinovich Ivanov
4 Leonid Nikolaevich Volkov
5 Vladimir Mihajlovich Semenov
Predopredelennaya peremennaya NR ravna nomeru obrabatyvaemoj
zapisi. My vospol'zovalis' ee znacheniem dlya numeracii
strok.
Primer 3. AWK-programma vyvodit polnoe chislo let na
1988 god kazhdomu licu iz spiska
{ print("\t", NR, $2, $3, $1, "\t\t", 1988 - $4); }
Posle vypolneniya programmy poluchim:
1 Sidor Sidorovich Sidorov 31
2 Petr Ivanovich Petrov 26
3 Mihail Konstantinovich Ivanov 23
4 Leonid Nikolaevich Volkov 38
5 Vladimir Mihajlovich Semenov 30
Primer 4. AWK-programma podschityvaet srednij vozrast i
srednyuyu zarabotnuyu platu perechislennyh v spiske lic
{
age += 1988 - $4;
pay += $6;
}
END {
print ("Srednij vozrast:\t", age/NR );
print ("Srednyaya zarplata:\t", pay/NR );
}
Posle vypolneniya programmy poluchim:
Srednij vozrast: 29.6
Srednyaya zarplata: 218
Kogda neobhodimo obespechit' vyvod rezul'tata po zaversheniyu
spiska zapisej, ispol'zuetsya selektor END. Peremennye age i
pay opredelyayutsya avtomaticheski kak chisla v moment pervogo
ispol'zovaniya. Vyrazheniya vychislyayutsya dlya vseh vhodnyh zapi-
sej.
Primer 5. AWK-programma podschityvaet srednie vozrast i
zarabotnuyu platu rabochih i sluzhashchih v spiske. Dlya vydeleniya
strok so svedeniyami o rabochih ispol'zuetsya shablon /rab/, o
sluzhashchih - shablon /sl/. SHablony soderzhat obrazcy dlya poiska
v polyah zapisi. Dannye vyvodyatsya posle obrabotki vseh
- 4 -
zapisej.
/rab/ {
rage += 1988 - $4;
rpay += $6;
r++;
}
/sl/ {
age += 1988 - $4;
pay += $6;
c++;
}
END {
print("\t\tSrednij vozrast Srednyaya zarplata\n");
print(" Rabochie:\t", rage/r, "\t", rpay/r );
print("Sluzhashchie:\t", age/c, "\t\t", pay/c );
}
Posle vypolneniya programmy poluchim:
Srednij vozrast Srednyaya zarplata
Rabochie: 30.3333 223.333
Sluzhashchie: 28.5 210
Programma vypolnyaetsya sleduyushchim obrazom. Esli zapis' v
kakom-libo iz polej soderzhit obrazec, vypolnyaetsya dejstvie,
zapisannoe v figurnyh skobkah ryadom s sootvetstvuyushchim shablo-
nom, inache dejstvie ne vypolnyaetsya. Dejstviya, ukazannye
posle END, vypolnyayutsya po koncu spiska zapisej. SHablony v
primere ispol'zuyutsya kak selektory vhodnyh zapisej: esli v
chetvertom primere dejstviya byli vypolneny dlya vseh vhodnyh
zapisej, to v etom - tol'ko dlya otobrannyh po obrazcam, uka-
zannym v shablonah. Pri etom END ispol'zuetsya kak selektor
special'nogo vida: on opredelyaet spisok operatorov AWK-
programmy, kotoryj dolzhen vypolnit'sya posle zaversheniya vhod-
nogo potoka zapisej.
Primer 6. AWK-programma vychislyaet urovni zarabotnoj
platy
- 5 -
BEGIN {
Min = 1000;
Max = 0;
}
{
if ( $6 << Min ) {
Min = $6;
smin = $1 " " $2 " " $3;
}
if ( $6 >> Max ) {
Max = $6;
smax = $1 " " $2 " " $3;
}
}
END {
print( "\t\tUrovni zarplaty\n" );
print( " Minimal'nyj: ", Min, " (",smin,")" );
print( "Maksimal'nyj: ", Max, " (",smax,")" );
}
Posle vypolneniya poluchim:
Urovni zarplaty
Minimal'nyj: 180 ( Ivanov Mihail Konstantinovich )
Maksimal'nyj: 280 ( Volkov Leonid Nikolaevich )
V etoj programme tri razdela. Pervyj razdel ispol'zuetsya dlya
ustanovki nachal'nyh znachenij peremennyh Max i Min eshche do
chteniya zapisej iz spiska. Special'nyj selektor BEGIN opre-
delyaet spisok operatorov AWK-programmy, kotoryj dolzhen
vypolnit'sya do analiza pervoj zapisi iz vhodnogo potoka. Vo
vtorom razdele osushchestvlyaetsya sobstvenno obrabotka zapisej.
Operatory etogo razdela programmy vypolnyayutsya dlya vseh vhod-
nyh zapisej, tak kak selektor ne ukazan. Tretij razdel
vypolnyaetsya kogda zavershaetsya spisok zapisej (selektor END).
V stroke
smin = $1 " " $2 " " $3;
peremennoj smin prisvaivayutsya znacheniya pervyh treh polej
zapisi, konkatenaciya kotoryh vmeste s probelami, ukazannymi
v kavychkah, obrazuet stroku. Takim obrazom znacheniem pere-
mennoj smin budet stroka simvolov tipa "Familiya Imya
Otchestvo".
Sushchestvuet neskol'ko sposobov vyzova interpretatora
awk. AWK-programma v fajle:
- 6 -
awk -f imya_fajla_s_AWK-programmoj vhodnoj_fajl ...
Po umolchaniyu razdelitelem zapisej yavlyaetsya simvol novoj
stroki, razdelitelem polej - simvol probela i/ili tabulyacii.
Simvoly-razdeliteli mozhno yavno opredelit' v programme.
Simvol-razdelitel' polej mozhno opredelit' i v komandnoj
stroke. Vyzov awk s ukazaniem simvola-razdelitelya polej:
awk -Frazdelitel' -f fajl_AWK-programma vhodnoj_fajl ...
CHasto AWK-programmy nastol'ko korotki, chto ih celesoobrazno
ukazyvat' neposredstvenno v komandnoj stroke, a ne v fajle.
Vyzov awk s programmoj v komandnoj stroke:
awk -Frazdelitel' 'AWK-programma' vhodnoj_fajl ...
awk 'AWK-programma' vhodnoj_fajl ...
Interpretator awk, kak i bol'shinstvo drugih programm sis-
temy, pozvolyaet vhodnoj_fajl zamenit' na standartnyj vvod.
awk -f imya_fajla_s_AWK-programmoj -
awk -Frazdelitel' 'AWK-programma' -
awk 'AWK-programma' -
Esli ne ukazano drugoe, rezul'tat vypolneniya AWK-programmy
pechataetsya na ekrane displeya.
2. Peremennye, vyrazheniya i prisvaivaniya v AWK-programmah
V yazyke AWK vydelyayut dve gruppy peremennyh: predoprede-
lennye i deklarirovannye v programme. Predopredelennye
peremennye dostupny dlya podstanovok i izmenenij v programme,
ih ishodnye znacheniya ustanavlivayutsya interpretatorom awk v
processe zapuska i vypolneniya AWK-programmy. K predoprede-
lennym peremennym otnosyatsya:
NR nomer tekushchej zapisi;
NF chislo polej v tekushchej zapisi;
RS razdelitel' zapisej na vvode (simvol);
FS razdelitel' polej zapisi na vvode (simvol);
ORS razdelitel' zapisej na vyvode AWK-programmy (simvol);
OFS razdelitel' polej zapisi na vyvode (simvol);
- 7 -
OFMT format vyvoda chisel;
FILENAME imya vhodnogo fajla (stroka).
Po umolchaniyu imeyut mesto sleduyushchie znacheniya predoprede-
lennyh peremennyh:
RS = "\0";
FS = 'probel(y) i/ili tabulyaciya';
OFS = FS;
ORS = RS;
OFMT = "%.6g";
Predopredelennym peremennym RS, FS, ORS, OFS, OFMT mozhno
prisvaivat' znacheniya v AWK-programme.
V yazyke AWK otsutstvuyut deklaraciya i yavnaya inicializa-
ciya peremennoj lyubogo tipa. Vsyakoj peremennoj do ee pervogo
ispol'zovaniya prisvaivaetsya znachenie "\0" - pustaya stroka.
Primenyayutsya sleduyushchie tipy peremennyh:
pozicionnaya peremennaya;
chislo s plavayushchej tochkoj;
stroka simvolov;
massiv.
Pozicionnaya peremennaya opredelyaet pole zapisi, soderzhimoe
kotorogo mozhet byt' otneseno k tipam "stroka" ili
"chislo_s_tochkoj" i ispol'zuetsya v vide
$nomer_polya_zapisi
$(vyrazhenie)
Nomer_polya_zapisi mozhet byt' znacheniem vyrazheniya. Znacheniem
pozicionnoj peremennoj $0 yavlyaetsya vsya zapis'.
Interpretator awk rassmatrivaet peremennuyu kak stroko-
vuyu do togo momenta, kogda neobhodimo vypolnit' nekotoruyu
operaciyu nad ee znacheniem. V zavisimosti ot konteksta tip
znacheniya peremennoj ostaetsya libo strokovym, libo preobrazu-
etsya k tipu chislo_s_tochkoj. V dvusmyslennyh sluchayah pere-
mennye rassmatrivayutsya kak strokovye. Stroki, kotorye ne
mogut byt' interpretirovany kak chisla, v chislovom kontekste
budut imet' chislovoe znachenie NOLX. Ustranit' dvusmyslen-
nost' mozhno yavnym ukazaniem tipa peremennoj pri prisvaivanii
ej znacheniya, naprimer:
- 8 -
name = 1 ; # prisvoeno znachenie 1.0
name = "1"; # prisvoeno znachenie stroki "1"
Pri interpretacii vyrazhenij sushchestvennuyu rol' igraet kon-
tekst, naprimer:
name = 3 + 2 ;
name = 3 + "2" ;
name = "3" + "2" ;
name = 3 + 2 + "yabloko grusha apel'sin";
name = "yabloko" + "grusha";
V etom primere v pervyh chetyreh sluchayah name ravno 5.0, v
pyatom - 0.
Massiv ne deklariruetsya, on nachinaet sushchestvovat' v
moment pervogo ispol'zovaniya. Indeksy v massive mogut imet'
lyuboe nenulevoe znachenie, vklyuchaya nechislovye stroki, eto
pozvolyaet ispol'zovat' associativnye massivy. Naprimer, v
privedennoj nizhe AWK-programme budet podschitano chislo upomi-
nanij ob avtomobilyah razlichnyh marok vo vhodnom tekste:
/ZIL/ { Avtomobili["ZIL"]++; }
/GAZ/ { Avtomobili["GAZ"]++; }
/VAZ/ { Avtomobili["VAZ"]++; }
END {
print("ZIL : ", Avtomobili["ZIL"]);
print("GAZ : ", Avtomobili["GAZ"]);
print("VAZ : ", Avtomobili["VAZ"]);
}
Massivy mozhno ispol'zovat' dlya organizacii takogo algoritma
obrabotki dannyh, v kotorom trebuetsya mnogokratnyj prosmotr
vhodnogo potoka zapisej. Naprimer, esli ne zabotit'sya o
razmerah operativnoj pamyati, to mozhno ves' vhodnoj fajl
zapisat' v vide massiva zapisej i po zaversheniyu vhodnogo
potoka pristupit' sobstvenno k obrabotke:
- 9 -
{
Massiv_zapisej[NR] = $0
}
END {
...
programma obrabotki massiva
...
}
V kachestve imeni (znacheniya) indeksa massiva mozhno ispol'zo-
vat' vyrazhenie, naprimer:
name["2" * $3]
V yazyke AWK ispol'zuyutsya operatory prisvaivaniya
= += -= *= /= %=
i arifmeticheskie operacii
+ - * / % ++ --
Oni imeyut tot zhe smysl, chto i v yazyke programmirovaniya Si.
Imeyutsya nekotorye osobennosti vypolneniya operacij srav-
neniya
<< <<= == != >>= >>
Esli oba operanda interpretiruyutsya kak chisla, to vypolnyaetsya
sravnenie chisel. Esli odin iz operandov yavlyaetsya strokoj
simvolov, a drugoj - chislom, to vypolnyaetsya sravnenie strok.
Sravnenie strok zaklyuchaetsya v poparnom sravnenii vnutrennih
kodov simvolov strok do pervogo neravenstva kodov ili do
zaversheniya odnoj iz strok. Rassmotrim primer:
{
if( $1 << $2 )
print(NR": $1 =", $1, "; $2 =", $2, "; $1 < $2");
if( $1 == $2 )
print(NR": $1 =", $1, "; $2 =", $2, "; $1 == $2");
if( $1 >> $2 )
print(NR": $1 =", $1, "; $2 =", $2, "; $1 > $2");
}
Dopustim, imeetsya sleduyushchij vhodnoj tekst:
- 10 -
2.01 2.02
2.01 abc
a b
aa b
aa ab
aa ba
abc ab
ab abc
ef abc
V rezul'tate vypolneniya programmy poluchim:
1: $1 = 2.01; $2 = 2.02; $1 < $2
2: $1 = 2.01; $2 = abc ; $1 < $2
3: $1 = a ; $2 = b ; $1 < $2
4: $1 = aa ; $2 = b ; $1 < $2
5: $1 = aa ; $2 = ab ; $1 < $2
6: $1 = aa ; $2 = ba ; $1 < $2
7: $1 = abc ; $2 = ab ; $1 > $2
8: $1 = ab ; $2 = abc ; $1 == $2
9: $1 = ef ; $2 = abc ; $1 > $2
V AWK-programmah mozhno ispol'zovat' sleduyushchie logiches-
kie operacii:
! (ne) || (ili) && (i)
Kak obychno, znacheniem vyrazheniya, soderzhashchego operacii otno-
sheniya i/ili logicheskie operacii, yavlyayutsya: istina (ne nol')
ili lozh' (nol'). Prioritety operacij v vyrazheniyah analo-
gichny ustanovlennym v yazyke Si. Dlya upravleniya poryadkom
vypolneniya operacij v vyrazhenii ispol'zuyutsya kruglye skobki.
V yazyke AWK imeetsya operaciya, ne predusmotrennaya v Si,
- eto operaciya "probel", kotoraya ispol'zuetsya dlya konkatena-
cii peremennyh, znacheniya kotoryh interpretiruyutsya kak stro-
kovye
name = "yabloko " "i grusha";
V etom sluchae znacheniem peremennoj name budet stroka vida
"yabloko i grusha"
Vmesto simvola probel mozhno ispol'zovat' simvol tabulyacii.
Pri ispol'zovanii operacii "probel" uchityvaetsya kontekst,
naprimer:
- 11 -
$1 = "yabloko"
$2 = "i"
$3 = "grusha"
name1 = $3 $2 $1; # 1
name2 = $3" "$2" "$1; # 2
name3 = "Krasnoe " $1; # 3
name4 = 1 2 3 4 5 6 7 8 9; # 4
name5 = 123 789; # 5
name6 = $3$2$1; # 6
name7 = $3 123; # 7
znacheniem peremennoj name1 budet stroka:
"grushaiyabloko"
Znacheniem peremennoj name2 budet stroka:
"grusha i yabloko"
Znacheniem peremennoj name3 budet stroka:
"Krasnoe yabloko"
Znacheniem peremennoj name4 budet stroka:
"123456789"
Znacheniem peremennoj name7 budet stroka:
"grusha123"
Znacheniem peremennoj name5 budet stroka:
"123789"
Iz primera 5 vidno, chto v kachestve znaka operacii "probel"
sushchestvenno nalichie lish' odnogo probela mezhdu operandami,
ostal'nye ignoriruyutsya. Znacheniem peremennoj name6 budet
stroka vida
"grushaiyabloko"
Odnako sintaksis, ispol'zovannyj v 6 stroke primera, somni-
telen i ne stoit polagat'sya na "mudrost'" interpretatora
awk.
Pozicionnye peremennye mozhno ispol'zovat' v vyrazheniyah
lyubogo vida, im mozhno prisvaivat' novye znacheniya. Rassmotrim
neskol'ko primerov:
- 12 -
$3 = $1 " " $2;
$3 += $1;
$3 = $3 $3 $3;
$3 = "";
$0 = $3;
V pervom sluchae pozicionnoj peremennoj $3 prisvaivaetsya
stroka, poluchennaya v rezul'tate konkatenacii znacheniya pozi-
cionnoj peremennoj $1, probela i znacheniya pozicionnoj pere-
mennoj $2. Vo vtorom sluchae znachenie peremennoj $3 uvelichi-
vaetsya na znachenie peremennoj $1. V tret'em sluchae vypolnya-
etsya konkatenaciya sobstvennogo znacheniya peremennoj $3, v
chetvertom - peremennoj $3 prisvaivaetsya znacheniie pustoj
stroki, v pyatom - znachenie peremennoj $0 (vsya zapis') zame-
nyaetsya znacheniem polya 3.
3. Struktura AWK-programmy
AWK-programma sostoit iz spiska pravil vida:
selektor1 { dejstvie }
...
selektorN { dejstvie }
Otkryvayushchaya figurnaya skobka dolzhna stoyat' v toj zhe stroke,
gde selektor. V lyubom meste programmy mozhno vvesti kommenta-
rij, on pechataetsya ot simvola # do konca stroki.
Kazhdoe pravilo vypolnyaetsya dlya kazhdoj zapisi iz vhod-
nogo potoka. Selektor ispol'zuetsya dlya togo, chtoby vydelit'
zapis', nad kotoroj budet vypolneno dejstvie sootvetstvuyu-
shchego pravila. Esli zapis' ne vydelena ni odnim iz selekto-
rov, ona ignoriruetsya i ne vyvoditsya na standartnyj vyvod.
Esli zapis' vydelena selektorom, vypolnyaetsya dejstvie soot-
vetsvuyushchego pravila. Esli nekotoruyu zapis' vydelyayut nes-
kol'ko selektorov, nad nej vypolnyayutsya dejstviya sootvetstvu-
yushchih pravil.
V pravile mozhet otsutstvovat' selektor, togda dejstvie
etogo pravila budet vypolneno dlya vseh bez isklyucheniya vhod-
nyh zapisej. V pravile mozhet otsutstvovat' dejstvie, togda
vse vydelennye selektorom zapisi budut napravleny na stan-
dartnyj vyvod bez izmenenij.
Opredeleny dva pravila special'nogo vida:
- 13 -
BEGIN { dejstvie }
...
spisok drugih pravil
...
END { dejstvie }
Pravilo s selektorom BEGIN vypolnyaetsya do chteniya pervoj
vhodnoj zapisi, s selektorom END - posle chteniya poslednej
zapisi. Pravilo s selektorom BEGIN dolzhno byt' pervym v
spiske pravil, s selektorom END - poslednim. Vozmozhno takoe
ispol'zovanie etih pravil:
BEGIN { dejstvie }
...
spisok drugih pravil
ili
spisok drugih pravil
...
END { dejstvie }
Dejstvie v pravile mozhet soderzhat' spisok operatorov i
upravlyayushchih konstrukcij. Operator dolzhen zakanchivat'sya sim-
volom ";", ili simvolom novoj stroki, ili zakryvayushchej skob-
koj.
Peremennuyu mozhno ispol'zovat' v lyubom pravile AWK-
programmy, nachinaya s mesta, gde ona opredelena. Rassmotrim
primer, v kotorom demonstriruyutsya osobennosti vypolneniya
pravil AWK-programmy i ispol'zovaniya peremennyh:
- 14 -
# Programma demonstriruet rabotu
# pravil razlichnogo vida i oblast'
# dejstviya peremennyh
# Pravilo 1 vypolnyaetsya
# dlya vseh zapisej
{ print("Zapis' nomer:", NR); }
# Pravilo 2 vypolnyaetsya tol'ko dlya
# zapisej, gde obnaruzhen obrazec aaa
/aaa/ {
print("Pravilo 2:");
print(" Vhod:", $0);
$1 = $1 $2;
$2 = "***";
A = $2;
print("Rezul'tat:", $0, "A =", A);
}
# Pravilo 3 vypolnyaetsya tol'ko dlya
# zapisej, gde obnaruzhen obrazec ddd
/ddd/ {
print("Pravilo 3:");
print(" Vhod:", $0);
$1 = $1 $3;
$2 = "&&&";
A = $2;
print("Rezul'tat:", $0, "A =", A);
}
# Pravilo 4 vypolnyaetsya dlya vseh zapisej
{
print("Pravilo 4:", $0, "A =", A,"\n");
}
Dopustim, na vhod etoj programme peredayutsya sleduyushchie tri
zapisi:
eee fff
ddd eee fff
aaa bbb ccc ddd eee
togda posle vypolneniya programmy poluchim:
- 15 -
Zapis' nomer: 1
Pravilo 4: eee fff A =
Zapis' nomer: 2
Pravilo 3:
Vhod: ddd eee fff
Rezul'tat: dddfff &&& fff A = &&&
Pravilo 4: dddfff &&& fff A = &&&
Zapis' nomer: 3
Pravilo 2:
Vhod: aaa bbb ccc ddd eee
Rezul'tat: aaabbb *** ccc ddd eee A = ***
Pravilo 3:
Vhod: aaabbb *** ccc ddd eee
Rezul'tat: aaabbbccc &&& ccc ddd eee A = &&&
Pravilo 4: aaabbbccc &&& ccc ddd eee A = &&&
4. Selektory
Selektor ukazyvaetsya, chtoby opredelit', budet li vypol-
nyat'sya dejstvie v pravile. V kachestve selektora mozhet byt'
ispol'zovano lyuboe vyrazhenie, shablon i proizvol'naya ih kom-
binaciya. Rassmotrim neskol'ko primerov ispol'zovaniya vyrazhe-
nij v selektorah:
$1 != $2 || $1 >> 128
vybrat' zapis', v kotoroj libo pervye dva polya raz-
lichny, libo soderzhimoe pervogo polya bol'she 128;
$1 % $2 == 1
vybrat' zapis', v kotoroj ostatok ot deleniya polej
raven 1;
NF % 2 == 0 || name << 2.2
vybrat' zapis', libo soderzhashchuyu chetnoe chislo polej,
libo esli peremennaya name men'she 2.2;
$1 == "Ivanov I.I."
vybrat' zapis', v kotoroj pervoe pole otnositsya k Iva-
novu I.I.;
$1 >>= "M" && $1 != "Moskva"
vybrat' zapis', pervoe pole kotoroj nachinaetsya s bukvy
M i dalee po alfavitu, no ne yavlyaetsya slovom Moskva.
SHablon ispol'zuetsya dlya formirovaniya odnogo ili bol'-
shego chisla obrazcov v selektore. Pri skanirovanii vhodnoj
zapisi osushchestvlyaetsya poisk cepochki simvolov, tozhdestvennoj
- 16 -
obrazcu. V prostejshem sluchae selektor s shablonom vyglyadit
sleduyushchim obrazom:
/obrazec/
V simvolah / ukazan obrazec, kotoryj budet ispol'zovan dlya
poiska. Sushchestvenno, chto lyuboj simvol, v tom chisle probel,
ukazannyj vnutri pary simvolov /, yavlyaetsya chast'yu obrazca.
Esli neobhodimo, chtoby sootvetstvie obrazcu opredelya-
los' v konkretnom pole zapisi, ispol'zuyutsya operatory soot-
vetstviya (~ i !~)
$nomer_polya ~ shablon
esli pri prosmotre ukazannoj pozicionnoj permennoj
obnaruzhivaetsya cepochka simvolov, tozhdestvennaya obrazcu
v shablone (operator ~), vypolnyaetsya dejstvie pravila.
$nomer_polya !~ shablon
esli pri prosmotre ukazannoj pozicionnoj permennoj ne
obnaruzhivaetsya cepochka simvolov, tozhdestvennaya obrazcu
v shablone (operator !~), vypolnyaetsya dejstvie pravila.
V obshchem sluchae shablon mozhet formirovat' mnozhestvo
obrazcov i/ili ukazyvat', v kakom meste zapisi neobhodimo
iskat' sootvetstvie vhodnoj cepochki simvolov obrazcu. Pri
neobhodimosti ispol'zuyutsya tak nazyvaemye regulyarnye vyrazhe-
niya, v etom sluchae shablon vyglyadit sleduyushchim obrazom:
/regulyarnoe_vyrazhenie/
V rezul'tate razbora regulyarnogo vyrazheniya interpretatorom
awk stroitsya i vypolnyaetsya algoritm poiska odnogo ili bol'-
shego chisla obrazcov vo vhodnoj zapisi.
Regulyarnye vyrazheniya v shablonah selektorov AWK analo-
gichny podobnym v lex, redaktore ed i v komande grep. Regu-
lyarnoe vyrazhenie formiruetsya kak kompoziciya cepochek simvolov
(i/ili diapozonov simvolov) i operatorov. Operatory v regu-
lyarnyh vyrazheniyah ukazyvayutsya v vide simvolov-operatorov.
CHtoby otnesti dejstvie simvola-operatora k otdel'nomu frag-
mentu regulyarnogo vyrazheniya, ispol'zuyutsya kruglye skobki.
CHtoby otmenit' special'noe znachenie simvola-operatora, ego
ekraniruyut simvolom \.
Dlya zapisi regulyarnyh vyrazhenij upotreblyayutsya sleduyushchie
simvoly-operatory:
^ ot nachala;
$ na konce;
- 17 -
. lyuboj simvol;
simvol
dannyj simvol, esli on ne simvol-operator;
\simvol
ispol'zovat' simvol-operator kak obychnyj simvol;
[stroka]
lyuboj iz simvolov dannoj stroki;
[bukva1-bukva2]
lyubaya bukva iz dannogo leksikograficheski uporyadochennogo
diapazona bukv;
[cifra1-cifra2]
lyubaya cifra iz dannogo diapazona cifr;
reg_vyrazhenie*
0 ili bolee vhozhdenij regulyarnogo vyrazheniya;
reg_vyrazhenie+
1 ili bolee vhozhdenij regulyarnogo vyrazheniya;
reg_vyrazhenie?
0 ili 1 vhozhdenie regulyarnogo vyrazheniya;
reg_vyrazhenie1 reg_vyrazhenie2
posledovatel'noe vhozhdenie reg_vyrazhenie1 i
reg_vyrazhenie2;
reg_vyrazhenie1|reg_vyrazhenie2
vhozhdenie reg_vyrazhenie1 ili reg_vyrazhenie2;
Rassmotrim neskol'ko primerov ispol'zovaniya regulyarnyh
vyrazhenij:
/^Ivanov/
vydelit' zapis', nachinayushchuyusya cepochkoj simvolov "Iva-
nov" Takim obrazom, budut vydeleny sluchai tipa "Iva-
novu", "Ivanovoj", ... ;
$3 ~ /^Ivanov/
vydelit' zapis', v kotoroj tret'e pole nachinaetsya
cepochkoj simvolov "Ivanov";
/([abc][ABC])$/
vydelit' zapis', predposlednim simvolom kotoroj yavlya-
etsya odna iz bukv abc i poslednim - odna iz bukv ABC;
/[0-9]+/
vydelit' zapis', soderzhashchuyu ne menee odnoj cifry;
- 18 -
$3 !~ /(Sidor)|(Petr)/
ne vydelyat' zapis', soderzhashchuyu v tret'em pole chto-libo
o Sidorah ili Petrah;
Nizhe priveden primer AWK-programmy, pechatayushchej imena
registracionnyh katalogov i imena vseh pol'zovatelej sis-
temy, kotorymi ne ustanovlen parol':
BEGIN {
FS = ":";
print("Imya\tKatalog");
}
$2 !~ /(([0-9])|([a-z])|([A-Z]))+/ {
print( $1, "\t", $6);
}
V pervom pravile (selektor BEGIN) menyaetsya razdelitel' polej
zapisi s probela na dvoetochie (takova struktura zapisej v
parol'nom fajle /etc/passwd operacionnoj sistemy DEMOS). Vo
vtorom pole zapisi parol'nogo fajla soderzhitsya zashifrovannyj
parol' - obychno eto kombinaciya cifr i bukv. Esli parol' ne
ustanovlen, to vtoroe pole zapisi pusto. |tot fakt ispol'zo-
van dlya formirovaniya selektora - vtoroe pole ne dolzhno
soderzhat' cifr i bukv. Selektor vydelyaet vtoroe pole zapisi
i proveryaet nalichie ne menee odnogo simvola v etom pole.
Esli pole pusto, vypolnyaetsya dejstvie, kotoroe zaklyuchaetsya v
pechati imeni pol'zovateya (pervoe pole) i imeni registracion-
nogo kataloga pol'zovatelya (shestoe pole).
Inogda neobhodimo opredelit' diapazon zapisej, dlya
kotoryh vypolnyaetsya dejstvie. Naprimer, neobhodimo vyvesti
na pechat' zapisi s nomerami ot 10 do 20 vklyuchitel'no. Ili,
dopustim, vyvesti na pechat' pole nomer 6 kazhdoj zapisi,
nachinaya s toj, v kotoroj vtoroe pole "Petr", do toj, v koto-
roj pyatoe pole "Sidor". Dlya opredeleniya diapazona zapisej v
selektorah ispol'zuetsya operaciya zapyataya. Do zapyatoj ukazy-
vaetsya selektor, vydelyayushchij pervuyu zapis' v diapazone, posle
zapyatoj - selektor, vydelyayushchij poslednyuyu zapis' v diapazone.
Takim obrazom, my imeem delo s sostavnym selektorom. Dlya
vseh zapisej diapazona vypolnyaetsya dejstvie pravila s sos-
tavnym selektorom.
Rassmotrim primer. Dopustim, imeetsya sleduyushchij fajl:
- 19 -
sss pole2 pole3 pole4 1
pole1 sss pole3 pole4 2
pole1 pole2 sss pole4 3
pole1 pole2 pole3 sss 4
ttt pole2 pole3 pole4 5
pole1 ttt pole3 pole4 6
pole1 pole2 ttt pole4 7
pole1 pole2 pole3 ttt 8
Dopustim, neobhodimo vyvesti na pechat' diapazon zapisej.
Otkryvaet etot diapazon zapis', vtoroe pole kotoroj "sss", i
zakryvaet zapis', tret'e pole kotoroj "ttt". Togda programma
vyglyadit sleduyushchim obrazom:
$2 ~ /sss/, $3 ~ /ttt/ {
print( $0 );
}
V rezul'tate vypolneniya poluchim:
pole1 sss pole3 pole4 2
pole1 pole2 sss pole4 3
pole1 pole2 pole3 sss 4
ttt pole2 pole3 pole4 5
pole1 ttt pole3 pole4 6
pole1 pole2 ttt pole4 7
V odnoj programme mozhno ukazat' neskol'ko pravil s sos-
tavnymi selektorami. Pri etom esli vydelennye diapazony
perekryvayutsya, to kazhdaya vydelennaya zapis' budet obrabaty-
vat'sya neskol'kimi pravilami. Naprimer, dlya togo zhe ishod-
nogo fajla ispol'zuetsya sleduyushchaya programma obrabotki:
$2 ~ /sss/, $3 ~ /ttt/ {
print( $0 );
}
$1 ~ /sss/, NR == 5 {
print($0, "*");
}
NR == 6, NR == 8 {
print( $0, "<-" );
}
V rezul'tate vypolneniya poluchim:
- 20 -
sss pole2 pole3 pole4 1 *
pole1 sss pole3 pole4 2
pole1 sss pole3 pole4 2 *
pole1 pole2 sss pole4 3
pole1 pole2 sss pole4 3 *
pole1 pole2 pole3 sss 4
pole1 pole2 pole3 sss 4 *
ttt pole2 pole3 pole4 5
ttt pole2 pole3 pole4 5 *
pole1 ttt pole3 pole4 6
pole1 ttt pole3 pole4 6 <-
pole1 pole2 ttt pole4 7
pole1 pole2 ttt pole4 7 <-
pole1 pole2 pole3 ttt 8 <-
CHtoby ustranit' effekt peresecheniya diapazonov vydelen-
nyh zapisej, tam, gde eto neobhodimo, mozhno ispol'zovat'
operator next. |tot operator prekrashchaet obrabotku tekushchej
zapisi, upravlenie peredaetsya na nachalo programmy i nachina-
etsya razbor sleduyushchej zapisi. Teper' programma budet imet'
vid:
$2 ~ /sss/, $3 ~ /ttt/ {
print( $0 );
next;
}
$1 ~ /sss/, NR == 5 {
print($0, "*");
next;
}
NR == 6, NR == 8 {
print( $0, "<-" );
}
V rezul'tate vypolneniya programmy poluchim:
sss pole2 pole3 pole4 1 *
pole1 sss pole3 pole4 2
pole1 pole2 sss pole4 3
pole1 pole2 pole3 sss 4
ttt pole2 pole3 pole4 5
pole1 ttt pole3 pole4 6
pole1 pole2 ttt pole4 7
pole1 pole2 pole3 ttt 8 *
Iz primera vidno, chto v ishodnom spiske ne nashlos' ni odnoj
zapisi, kotoraya byla by obrabotana vsemi pravilami i dejst-
vie tret'ego pravila programmy ne vypolnyalos' voobshche.
- 21 -
Esli v rezul'tate vypolneniya pravila s sostavnym selek-
torom vydeleno nachalo diapazona zapisej, no ne vydelen ego
konec, dejstvie etogo pravila vypolnyaetsya dlya vseh zapisej
do konca vvoda. Esli zhe ne obnaruzhena zapis', otkryvayushchaya
diapazon zapisej, to dejstvie pravila s sostavnym selektorom
ne vypolnyaetsya.
5. Dejstviya
Dejstviya v pravilah AWK-programmy opredelyayut algoritm
obrabotki vydelennyh selektorom zapisej. Dlya zapisi algo-
ritma ispol'zuyutsya prisvaivaniya, vyrazheniya, operatory uprav-
leniya, operatory vyvoda, vstroennye funkcii.
Vyshe bylo pokazano, chto dejstvie v pravile zapisyvaetsya
kak blok (v smysle yazyka programmirovaniya Si). Figurnaya
skobka, otkryvayushchaya blok, dolzhna ukazyvat'sya v toj zhe
stroke, chto i selektor, zakryvayushchaya - po zaversheniyu bloka. V
obshchem sluchae blok mozhet byt' pustym, togda, kak eto bylo
skazano vyshe, vse zapisi, vydelennye selektorom, peredayutsya
na standartnyj vyvod bez preobrazovanij.
K chislu operatorov upravleniya otnosyatsya:
exit
zavershit' vypolnenie programmy;
next
perejti k chteniyu sleduyushchej zapisi. Upravlenie pereda-
etsya na pervoe pravilo AWK-programmy (esli imeetsya pra-
vilo s selektorom BEGIN, to na sleduyushchee za nim);
break
preryvaet vypolnenie ohvatyvayushchego cikla. Upravlenie
peredaetsya na operator, sleduyushchij za ciklom;
continue
perehod k sleduyushchej iteracii cikla;
if(vyrazhenie) { blok_1 } else { blok_2 }
esli znachenie vyrazheniya - istina, vypolnyayutsya operatory
bloka_1, inache operatory bloka_2. CHast' else mozhno
opustit'. Esli blok_1 ili blok_2 soderzhat po odnomu
operatoru, figurnye skobki mozhno ne ukazyvat';
while(vyrazhenie) { blok }
operatory bloka vypolnyayutsya, poka znachenie vyrazheniya -
istina. Esli v bloke tol'ko odin operator, figurnye
skobki mozhno ne ukazyvat';
for(vyrazhenie_1; vyrazhenie_2; vyrazhenie_3) { blok }
esli znachenie vyrazheniya_2 - istina, vypolnyayutsya
- 22 -
operatory bloka. Vyrazhenie_1 vychislyaetsya pered pervoj
iteraciej cikla, vyrazhenie_3 vychislyaetsya na kazhdoj ite-
racii cikla. Esli blok soderzhit odin operator, figurnye
skobki mozhno ne ukazyvat'.
for( indeks in imya_massiva ) { blok }
dlya kazhdogo znacheniya indeksa massiva vypolnyayutsya opera-
tory bloka. Znachenie indeksa formiruetsya avtomaticheski
na kazhdoj iteracii cikla i ravno znacheniyu, eshche ne
ispol'zovannomu v cikle. Esli ispol'zuetsya associativ-
nyj massiv, indeks formiruetsya v leksikograficheskom
poryadke. Esli v bloke proishodit dobavlenie elementov
massiva, rezul'tat vypolneniya cikla nepredskazuem. Esli
v bloke izmenyaetsya znachenie indeksa, rezul'tat vypolne-
niya cikla nepredskazuem. Vmesto indeksa i/ili imeni
massiva mozhno ukazat' vyrazhenie, znachenie kotorogo
interpretiruetsya kak indeks i/ili imya massiva.
V kachestve uslovnyh vyrazhenij mozhno ispol'zovat' lyubye
iz opisannyh vyshe. V vyrazheniyah mozhno primenyat' shablony,
operatory ~ i !~. Rassmotrim primer:
/aaa/ {
if( $3 !~ /fff/ )
print( $0 );
}
V zapisi, vydelennoj po selektoru /aaa/, proveryaetsya soot-
vetstvie soderzhimogo polya $3 shablonu /fff/. Esli sootvets-
vie ne obnaruzheno, pechataesya vsya zapis', inache operator
print ne vypolnyaetsya.
Teper' rassmotrim primer ispol'zovaniya cikla for po
ideksu v associativnom massive. Dopustim, imeetsya spisok
zapisej
aaa aaa ddd ccc
ccc ddd
bbb ddd ddd
ccc
i pust' vypolnyaetsya programma
- 23 -
/bbb/ { m["bbb"]++; }
/ccc/ { m["ccc"]++; }
/aaa/ { m["aaa"]++; }
/ddd/ { m["ddd"]++; }
END { for( i in m )
print("m["i"] =", m[i]);
}
V kazhdom iz pervyh chetyreh pravil selektorami vydelyayutsya
zapisi i podschityvaetsya chislo takih zapisej v associativnom
massive s imenem m. Cikl for vypolnyaetsya po zaversheniyu
spiska vhodnyh zapisej. V rezul'tate vypolneniya programmy
poluchim:
m[aaa] = 1
m[bbb] = 1
m[ccc] = 3
m[ddd] = 3
Znacheniem kazhdogo elementa massiva yavlyaetsya chislo vydelennyh
selektorami zapisej. V rezul'tate vypolneniya cikla po
indeksu v associativnom massive poluchen vyvod znachenij ele-
mentov massiva v leksikograficheskom poryadke znachenij
indeksa.
Nizhe priveden primer programmy, dejstviya kotoroj soder-
zhat primery ispol'zovaniya osnovnyh upravlyayushchih konstrukcij.
Dopustim, imeetsya sleduyushchij tekst:
aaa, aaa, aaa aaa aaa.
aaa aaa, aaa, aaa aaa.
aaa aaa aaa, aaa aaa.
aaa aaa aaa aaa, aaa.
aaa; aaa aaa aaa: aaa.
aaa aaa; aaa aaa aaa.
aaa aaa aaa; aaa; aaa.
aaa aaa: aaa aaa; aaa.
aaa: aaa aaa; aaa aaa.
aaa aaa aaa: aaa: aaa.
Trebuetsya poluchit' nekotoruyu statistku o tekste:
- 24 -
# Programma vychislyaet statisticheskie
# harakteristiki teksta.
# Razdelitel' zapisej tochka.
# Razdelitel' polej probel.
# Vyvod rezul'tatov osushchestvlyaetsya
# posle zaversheniya vhodnogo teksta.
BEGIN {
# vydelenie i inicializaciya
# peremennyh
RS = "."; # razdelitel' zapisej
Nw = 0; # chislo slov
Nb = 0; # chislo simvolov v slovah
Np = 0; # chislo zapyatyh
Nd = 0; # chislo dvoetochij
Nt = 0; # chislo tochek s zapyatoj
}
{
for( i = 1; i <<= NF; i++ ){
if( $i ~ /,$/ ) {
Np++;
Nb--;
}
# Nb--; ne uchityvat' v dline
# slova znak prepinaniya
if( $i ~ /:$/ ) {
Nd++;
Nb--;
}
if( $i ~ /;$/ ) {
Nt++;
Nb--;
}
Nb += length( $i ); # dlina slova
Nw++; # uvelichit' chislo slov
}
}
END {
print("CHislo zapyatyh =", Np);
print("CHislo dvoetochij =", Nd);
print("CHislo tochek s zapyatoj =", Nt);
print("CHislo slov =", Nw);
print("CHislo simvolov v slovah =", Nb);
print("CHislo predlozhenij =", NR );
print("Srednyaya dlina predl. =", Nw/NR,"(slov)");
print("Srednyaya dlina slova =", Nb/Nw);
- 25 -
}
Nizhe pokazan rezul'tat raboty programmy:
CHislo zapyatyh = 6
CHis