8. gyakorlat

Mi az awk?

  • Tulajdonképpen ez is egy stream editor, mint a sed, azonban sokkal többet/mást tud
  • Egy önálló kis programnyelv
  • A szintakszisa hasonlít a C nyelvéhez
  • Szokták azt is mondani, hogy a C nyelv szövegfeldolgozásra kihegyezett változata
  • Az awk is képes fogadni standard inputról adatokat, vagy paraméterként megadott fileokat dolgoz fel
    ... | awk '{ parancsok }'
    awk '{ parancsok }' f1 f2 f3
  • Arra is van lehetőségünk (hasonlóan a grep-hez vagy a sed-hez), hogy előre megírjuk az awk programunkat, ezt elmentsük egy file-ba, és onnan töltsük be ha használni akarjuk
    ... | awk -f programfile.awk

Hogyan működik?

  • Az awk a feldolgozandó szöveget részekre bontja
  • Hasonlóan a többi linuxos programhoz a feldolgozás itt is soronként történik a sorokat pedig mezőkre bontja
  • Alapértelmezésben a mező egy sornak olyan része, amit a környezetétől elől és hátul egyaránt legalább egy-egy szóköz vagy tabulátor választ el.
  • Miután az awk mezőkre bontotta a fedolgozandó sort, végrehajtja rajta a teljes programot
  • Fontos tehát: az awk fogja a feldolgozandó filet és minden sorára a következő két lépést hajtja végre:
    1. mezőkre bontás
    2. az awk program végrehajtása
  • Megjegyezzük még: az adott sorban található i. mezőre $i-vel tudunk hivatkozni

Kiiratás (print)

Tetszőleges szöveget az awk-n belül a stdout-ra a print utasítással írhatunk ki

ls -l | awk '{ print $8 }' ls -l | awk '{ print "Név: " $8 }' cat lista.txt | awk '{ print $2" "$1 }' cat lista.txt | awk '{ print $2,$1 }' cat lista.txt | awk '{ print $0 }' cat lista.txt | awk '{ print }' cat lista.txt | awk '{ print "" }' cat lista.txt | awk ' /[a-z]\+[0-9]/ { print $0 }'

Belső változók

Név Leírás Alap.érték
RS Record elválasztó karakter (Record separator) Újsor
ORS Kimeneti RS Újsor
FS Mezőelválasztó karakter (Field Separator) Space + Tab
OFS Kimeneti FS Space
NR A pillanatnyi sor szám (Number of Row) Nincs
NF A mezők száma a pillanatnyi sorba (Number of Fields)Nincs

Természetesen ezen változóknak adhatunk új értéket.
Alapvetően mindegyik egy-egy karakter, de megadhatunk több karaktert is, ekkor azonban szabályos kifejezésként kerül kiértékelésre
Például alapértelmezés szerint az FS így néz ki: FS="[ \t]+"
Megjegyzés: az FS="" beállítással az input szöveg sorait karakterenként tudjuk elérni

Változók használata

  • Hasonlóan a környezeti változókhoz, itt sem kell előre deklarálni a változókat "csak használjuk" őket
  • Itt sem kell típust megadnunk
  • Viszont van egy fontos különbség:
    			bash		awk
    			x=10		x=10
    			echo $x		print x
    		

Az awk program szerkezete - blokkok

  • Eddig arról beszéltünk, hogy az awk program az input minden sorára újra és újra lefut
  • Van két speciális blokk, amelyek csak egyszer futnak le

BEGIN blokk

A tényleges feldolgozást végző "főprogram" előtt hajtódik végre (egyszer!)
A BEGIN blokkba helyezhetünk el különféle inicializáló utasításokat/értékadásokat (pl FS beállítás, változók kezdőérékének beállítása stb.)

END blokk

A "főprogram" után hajtódik végre (szintén egyszer!)
Az END blokkban esetleg vmilyen kiiratás vagy egyéb "rendrakó" utasítások kerülhetnek

Egy általános awk program felépítése

... | awk 'BEGIN { bevezető műveletek } { főprogram } END { záró műveletek }'

Példák

ls -l | grep '^-' | awk 'BEGIN {meret=0} {meret=meret+$5} END {print meret}' ls -l | awk 'BEGIN {meret=0} /^-/ {meret=meret+$5} END {print meret}' ls -l | awk \ 'BEGIN {max=0} /^-/{ if($5>max) { max=$5 nev=$8 } } END { print "A legnagyobb fájl: " nev "\n Mérete: "max}'

Szintaxis

Elágazás

Ugyanaz a szintaxis, mint C-ben

if (feltétel) { utasítások } else { utasítások }

  • A feltétel azonban nem csak a C-ben megszokott feltétel lehet
  • Vizsgálható vele szabályos kifejezésre való illeszkedés
  • Az illeszkedést a '~' karakter jelöli
  • Vizsgálhatunk "nem illeszkedést" is, a '!~' jelöléssel

ls -l | awk \ 'BEGIN { meret=0 } { if ( $0 !~ /^d/ ) meret += $5 } END { print meret }'

Ciklusok

for és while ciklus: ugyanúgy, mint C-ben

awk 'BEGIN { for(i = 1; i < 11 ; i++) print i }' awk 'BEGIN { i=0 while(i < 10) { print i i = i + 1 } }'

Érdekességek

  • Az előbb láttunk két példát, amikor az awk-t önmagában használtunk
  • Ilyen esetben vagy BEGIN vagy END blokkba írjuk a kódot, hiszen a "főprogram" az input minden sorára végrehajtódik, azaz pontosan annyiszor, ahány sor van, jelen esetben 0
  • Előfordulhat, hogy ha csak BEGIN blokkot használunk, akkor is "kér" vmilyen inputot az awk

    echo | awk 'BEGIN { for(i=1; i<11; i++) print i }'

  • Ha csak END blokkot használunk, akkor az újabb awk-k szintén elvárják az inputot

Stringek

  • length : string hossza
    length($0)
  • substr(string,start,hossz)
  • tolower(str)
  • toupper(str)

echo "egy kettőre" | awk \ '{ szoveg1=$1 szoveg2=$2 szoveg3=(szoveg1""szoveg2) # szoveg3=szoveg1szoveg2 NEM JÓ # vagy írhattunk volna szoveg3=(szoveg1)(szoveg2) -t is print szoveg3 }'

Példák

Átlagszámítás

Tegyük fel, hogy van 2 állományunk: l1.txt, l2.txt.
A fileok az egyes tanulok progkör jegyeit tartalmazzák. (l1.txt -> "normál zh" l2.txt -> javító zh)
Pl:

		     Kovács István  3
		     Stréber Elemér 5
		     Lusta János    1
		  

Feladat: számítsuk ki az egyes emberek átlagát!

#!/bin/bash cat l?.txt | sort | awk \ '{ if (NR == 1) { db = 1 sum = $3 nev = $1" "$2 } if (nev == $1" "$2) { sum = sum + $3 db++ } else { print nev, sum/db nev = $1" "$2 sum = $3 db = 1 } } END { print nev, sum/db }'

Feladat: Írjuk ki a képernyőre az f.txt fájl leghosszabb sorát

#!/bin/bash cat f.txt | awk \ 'BEGIN { MAX = 0; SOR="" } { if (length($0) > MAX) { SOR = $0 MAX = length($0) } } END { print SOR }'