Tutorial awk
La materia SO[1. Sisteme de operare] învățăm printre altele Unix, unelte Unix și avem și teme cu anumite scripturi. Printre altele, sed, grep și awk. La primele două nu am fost pe fază și nu am scris tutorial, dar voi încerca să explic un pic awk acuma (pentru că există greșeli în documentația pe care ne-a dat-o proful).
Awk este un limbaj de scripting specializat pe prelucrarea datelor de tip text. Awk consideră un fișier ca fiind format din înregistrări (delimitate prin ’n’, adică linie nouă Unix-style, dar se poate schimba), iar fiecare înregistrare are câmpuri, care sunt delimitate prin spațiu deobicei (dar se poate schimba aceasta). Un program awk constă din:
condition { action }
Interpretorul trece peste fiecare linie din fișierele de intrare și, dacă condiția este adevărată, execută acțiunile asociate. Acțiunile sunt secvențe de forma:
if( expression ) statement [ else statement ]
while( expression ) statement
for( expression ; expression ; expression ) statement
for( var in array ) statement
do statement while( expression )
break
continue
{ [ statement ... ] }
expression # commonly var = expression
print [ expression-list ] [ > expression ]
printf format [ , expression-list ] [ > expression ]
return [ expression ]
next # skip remaining patterns on this input line
nextfile # skip rest of this file, open next, start at top
delete array[ expression ]# delete an array element
delete array # delete all elements of array
exit [ expression ] # exit immediately; status is expression
În expresii putem folosi toți operatorii clasici. Variabilele sunt automat inițializate cu stringul gol sau cu 0, în funcție de necesități. Există câteva variabile și funcții speciale (nu o să le enumăr pe toate, read man for that):
FS: expresie regulară care definește cu ce se separă câmpurile
NF: numărul de câmpuri din înregistrarea curentă
NR: numărul ordinal al înregistrării curente. Se referă la numărul global, adică câte linii au fost procesate până acum, nu la numărul liniei din cadrul fișierului curent
FNR: numărul înregistrării în fișierul curent
FILENAME: ghici
ARGC: numărul de argumente de la linia de comandă
ARGV: tabloul cu argumente
length(string): Returnează lungimea stringului
substr(string,start,[len]): Returnează un string trunchiat conform parametrilor
Patternurile (șabloanele) sunt formate din expresii regulate și expresii relaționale (comparatii) care se aplica campurilor si care determina asupra căror linii se aplica acțiunile date. Două patternuri mai speciale sunt BEGIN și END, care sunt adevărate înainte de prima linie citită, respectiv după ultima linie citită (global, nu pe fișier!). Mai este si patternul gol, care se aplica la orice linie. Sunt două moduri de a folosi programe awk: primul de a da ca parametru la awk secvența de instrucțiuni. Acesta devine destul de urât în momentul în care avem programe mai lungi. A doua metodă este să îi dăm la awk un fișier „scenariu”, care conține instrucțiunile:
awk 'instructions' file1 file2 awk -f file_scen file1 file2
unde file1 și file2 sunt fișierele pe care vrem să executăm programul nostru.
Și acum să trecem la învățatul concret, pe exemple:
Sa se afiseze liniile din fisierele date ca parametru care contin un acelasi cuvint aflat in pozitii consecutive. Pentru liniile respective sa se afiseze si numarul liniei in cadrul fisierului din care face parte.
{
word = "" # resetam cuvantul memorat la inceputul fiecarei linii
for (i = 0; i< NF; i++) { # trecem peste toate liniile
if (word == $(i+1) ) { # $(i+1) se refera la campul al i+1-lea din rand
print "Fisierul " FILENAME ", linia " FNR ": " $0
break
}
word = $(i+1) # schimbam cuvantul memorat la campul curent
}
}
Sa se afiseze din fiecare fisier dat ca parametru numerele liniilor care au lungimea cel putin 10. De asemenea sa se afiseze continutul liniilor respective, mai putin primele 10 caractere. La terminarea analizei unui anumit fisier se va afisa numele fisierului si numarul de linii care au fost afisate.
BEGIN { # regula care se va executa doar la inceput
filename = ARGV[1] # initializam variabila cu a doua compononeta a parametrilor
# de la linia de comanda, deci cu primul fisier pe care va opera awk
# deoarce FILENAME inca nu a fost initializat
}
{
if (FILENAME!=filename) { # cand trecem la un fisier nou afisam contorul, numele
# fisierului si resetam variabilele
print "In the " filename " there were " count " lines longer than 10 characters"
count=0
filename=FILENAME
}
if (length($0) > 10) { # $0 se refera la tot sirul
print "Line " FNR " is longer than 10 characters: " substr($0,10) # FNR ne zice pe ce linie suntem in cadrul fisierului curent
count++
}
}
END { # la sfarsit afisam statisticile despre ultimul fisier pe care am lucrat
print "In the " filename " there were " count " lines longer than 10 characters"
}
Sa se afiseze numarul de fisiere, numarul total de cuvinte si numarul mediu de cuvinte din fisierele date ca parametri.
BEGIN {
filename = ARGV[1]
count = 1
}
{
if (filename != FILENAME) {
filename = FILENAME
count++
}
wordCount += NF # NF contine cate campuri (deci cuvinte in cazul nostru) sunt pe linia curenta
}
END {
print "Au fost " count " fisiere "
print "Numarul total de cuvinte este " wordCount ", iar media este " wordCount/count
}
Edit: 4. Pentru fiecare fisier dat ca parametru al comenzii awk, sa se afiseze numarul maxim de linii consecutive identice din fisier. Se va afisa continutul liniei, numarul de repetari si numele fisierului.
BEGIN {
filename = ARGV[1]
linie = ""
count = 0
max = 0
}
{
if (filename != FILENAME) {
if (count > max)
max = count
print "In fisierul " filename " cea mai repetata linie este " linie " care se repeta de " max " ori"
count = 0
linie = ""
filename = FILENAME
}
if (linie != $0 ) {
linie = $0
print "max1 " max " count " count
if (count > max)
max = count
count = 1
print "max2 " max " count " count
}
else {
count = count +1
}
}
END {
if (count > max)
max = count
print "In fisierul " filename " cea mai repetata linie este " linie " care se repeta de " max " ori"
}
Sper că v-a fost de folos acest tutorial. Dacă aveți nelămuriri, lăsați un comment mai jos.