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 doc­u­men­tația pe care ne-a dat-o proful).

    Awk este un limbaj de scripting spe­cial­izat pe pre­lu­crarea datelor de tip text. Awk consideră un fișier ca fiind format din în­reg­istrări (delimitate prin ’n’, adică linie nouă Unix-style, dar se poate schimba), iar fiecare în­reg­is­trare are câmpuri, care sunt delimitate prin spațiu deobicei (dar se poate schimba aceasta). Un program awk constă din:

    condition { action }

    In­ter­pre­torul 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. Vari­abilele sunt automat in­ițial­izate 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 în­reg­is­trarea curentă

    NR: numărul ordinal al în­reg­istră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 în­reg­istră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 para­metrilor

    Pat­ter­nurile (șabloanele) sunt formate din expresii regulate și expresii re­laț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 in­strucți­u­ni. 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 in­strucți­u­nile:

     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 con­sec­u­tive. 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 con­sec­u­tive 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.