Weboldal keresés

AWK oktatóanyag: 25 gyakorlati példa az AWK parancsra Linuxban


Kíváncsi vagy, hogyan kell használni az AWK parancsot Linuxon? Íme 25 AWK-példa megfelelő magyarázattal, amelyek segítenek elsajátítani az AWK alapjait.

Az AWK parancs a Unix korai idejére nyúlik vissza. A POSIX szabvány része, és minden Unix-szerű rendszeren elérhetőnek kell lennie. És tovább.

Bár néha hiteltelenné válik a kora vagy a funkciók hiánya miatt egy többcélú nyelvhez, például a Perlhez képest, az AWK továbbra is olyan eszköz, amelyet szívesen használok a mindennapi munkám során. Néha viszonylag összetett programok írásához, de az erőteljes egysoros programozás miatt is írhat, hogy megoldja az adatfájlokkal kapcsolatos problémákat.

Tehát ennek a cikknek pontosan ez a célja. Megmutatja, hogyan tudja kihasználni az AWK teljesítményét kevesebb mint 80 karakterben hasznos feladatok elvégzéséhez. Ez a cikk nem egy teljes AWK oktatóanyag, de az elején mégis mellékeltem néhány alapvető parancsot, így még akkor is, ha kevés vagy nincs korábbi tapasztalatod, megragadhatod az alapvető AWK koncepciókat.

Példafájljaim ehhez az AWK-oktatóanyaghoz

A cikkben leírt összes egysorost ugyanazon az adatfájlon teszteljük:

cat file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

A fájl másolatát online szerezheti be a GitHubon.

Ismerje meg az előre meghatározott és automatikus változókat az AWK-ban

Az AWK néhány előre definiált és automatikus változót támogat a programok megírásában. Közülük gyakran találkozhat:

RS –A rekordelválasztó. Az AWK rekordonként dolgozza fel az Ön adatait. A rekordelválasztó a bemeneti adatfolyam rekordokra való felosztására szolgáló határoló. Alapértelmezés szerint ez az újsor karakter. Tehát ha nem változtatja meg, akkor a rekord a bemeneti fájl egyik sora.

NR – Az aktuális bemeneti rekord száma. Ha szabványos újsor-határolót használ rekordjaihoz, ez megegyezik az aktuális bemeneti sorszámmal.

FS/OFS –A mezőelválasztóként használt karakter(ek). Amint az AWK beolvas egy rekordot, felosztja azt különböző mezőkre az FS értéke. Amikor az AWK rekordot nyomtat a kimenetre, újra csatlakozik a mezőkhöz, de ezúttal az OFS elválasztót használja az FS elválasztó helyett. Általában az FS és az OFS ugyanaz, de ez nem kötelező. A „fehér szóköz” az alapértelmezett érték mindkettőnél.

NF – Az aktuális rekord mezőinek száma. Ha a szabványos „fehér szóköz” határolót használja a mezőkhöz, ez megegyezik az aktuális rekordban lévő szavak számával.

Vannak más többé-kevésbé szabványos AWK-változók is, ezért érdemes megnézni az adott AWK megvalósítási kézikönyvet további részletekért. Ez a részhalmaz azonban már elég ahhoz, hogy érdekes egysoros írásokat kezdjünk.

A. Az AWK parancs alapvető használata

1. Nyomtasson ki minden sort

Ez a példa többnyire haszontalan, de ennek ellenére jó bevezető lesz az AWK szintaxisban:

awk '1 { print }' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

Az AWK programok egy vagy több pattern { action } utasításból állnak.

Ha a bemeneti fájl adott rekordjára („sora”), a minta egy nem -nulla érték (az AWK-ban az „igaz” értékkel egyenértékű), a megfelelő műveleti blokk parancsai végrehajtásra kerülnek. A fenti példában, mivel az 1 egy nem nulla állandó, a { print } műveletblokk végrehajtásra kerül minden bemeneti rekordnál.

Egy másik trükk, hogy a { print } az alapértelmezett műveletblokk, amelyet az AWK fog használni, ha nem ad meg kifejezetten. Tehát a fenti parancs így rövidíthető:

awk 1 file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

Szinte haszontalan, a következő AWK program fogyasztja a bemenetét, de nem ad semmit a kimenetre:

awk 0 fájl

2. Távolítsa el a fájl fejlécét

awk 'NR>1' file
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

Ne feledje, ez a kifejezett írás megfelelője:

awk 'NR>1 { print }' file
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

Ez az egysoros a bemeneti fájl rekordjait fogja írni, kivéve a legelsőt, mivel ebben az esetben a feltétel 1>1, ami nyilvánvalóan nem igaz.

Mivel ez a program az RS alapértelmezett értékeit használja, a gyakorlatban eldobja a bemeneti fájl első sorát.

3. Nyomtasson vonalakat egy tartományban

Ez csak az előző példa általánosítása, és nem érdemel sok magyarázatot, kivéve azt, hogy a && a logikai és operátor:

awk 'NR>1 && NR < 4' file
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team

4. Csak szóközt tartalmazó sorok eltávolítása

awk 'NF' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support
17,05 apr 2019,abhishek,guest

Az AWK minden rekordot mezőkre bont az FS változóban megadott mezőelválasztó alapján. Az alapértelmezett mezőelválasztó az egy vagy több fehér szóköz karakter (más néven szóközök vagy tabulátorok). Ezekkel a beállításokkal minden rekord, amely legalább egy nem szóköz karaktert tartalmaz, legalább egy mezőt tartalmaz.

Más szóval, az egyetlen olyan eset, amikor az NF 0 („hamis”), az az, amikor a rekord csak szóközöket tartalmaz. Tehát ez az egysoros csak azokat a rekordokat nyomtatja ki, amelyek legalább egy nem szóköz karaktert tartalmaznak.

5. Az összes üres sor eltávolítása

awk '1' RS='' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support

17,05 apr 2019,abhishek,guest

Ez az egysoros egy homályos POSIX-szabályon alapul, amely meghatározza, ha az RS üres karakterláncra van állítva, „akkor a rekordokat egy <newline> pluszból álló sorozatok választják el. egy vagy több üres sor. ”

Érdemes megemlíteni a POSIX terminológiában, hogy az üres sor egy teljesen üres sor. A csak szóközt tartalmazó sorok nem számítanak „üresnek”.

6. Mezők kinyerése

Valószínűleg ez az egyik leggyakoribb AWK használati eset: az adatfájl egyes oszlopainak kibontása.

awk '{ print $1, $3}' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
        ,
,
,
17,abhishek

Itt mind a bemeneti, mind a kimeneti mezőelválasztót kifejezetten kómára állítottam. Amikor az AWK egy rekordot mezőkre bont, az első mező tartalmát a $1-be, a második mező tartalmát a $2-be és így tovább. Itt nem használom, de érdemes megemlíteni, hogy 0 dollár a teljes rekord.

Ebben az egysorosban talán észrevetted, hogy minta nélküli akcióblokkot használok. Ebben az esetben a minta 1-et („igaz”) feltételez, így a műveleti blokk minden rekordra végrehajtásra kerül.

Az Ön igényeitől függően előfordulhat, hogy az üres vagy csak szóközt tartalmazó sorok esetén nem azt eredményezi, amit szeretnénk. Ebben az esetben a második verzió lehetne egy kicsit jobb:

awk 'NF { print $1, $3 }' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
        ,
17,abhishek

Mindkét esetben az FS és az OFS egyéni értékeit adtam át a parancssorban. Egy másik lehetőség egy speciális BEGIN blokk használata az AWK programon belül a változók inicializálására az első rekord olvasása előtt. Tehát ízlésedtől függően inkább ezt írhatod:

awk 'BEGIN { FS=OFS="," } NF { print $1, $3 }' file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
        ,
17,abhishek

Itt érdemes megemlíteni, hogy az utolsó rekord beolvasása után is használhat END blokkokat bizonyos feladatok végrehajtására. Mintha csak most látnánk. Ennek ellenére elismerem, hogy ez messze nem tökéletes, mivel a csak szóközöket tartalmazó sorokat nem kezelik elegánsan. Hamarosan látni fogjuk a lehetséges megoldást, de előtte számoljunk egy kicsit…

7. Számítások elvégzése oszloponként

Az AWK támogatja a szabványos aritmetikai operátorokat. A kontextustól függően automatikusan konvertálja az értékeket szöveg és szám között. Ezenkívül használhatja saját változóit a közbenső értékek tárolására. Mindez lehetővé teszi kompakt programok írását az adatoszlopokon végzett számítások elvégzéséhez:

awk '{ SUM=SUM+$1 } END { print SUM }' FS=, OFS=, file
263

Vagy hasonlóképpen a += rövidített szintaxist használva:

awk '{ SUM+=$1 } END { print SUM }' FS=, OFS=, file
263

Kérjük, vegye figyelembe, hogy az AWK-változókat nem kell deklarálni használat előtt. Feltételezzük, hogy egy meghatározatlan változó tartalmazza az üres karakterláncot. Ami az AWK típusú konverziós szabályok szerint egyenlő a 0 számmal. Emiatt a funkció miatt nem foglalkoztam kifejezetten azzal az esettel, amikor a $1 szöveget (a fejlécben), szóközt vagy csak semmit nem tartalmaz. Minden ilyen esetben 0-nak számít, és nem zavarja az összegzésünket. Persze más lenne, ha helyette szorzást végeznék. Szóval, miért nem használja a megjegyzés rovatot arra, hogy megoldást javasoljon erre az esetre?

8. A nem üres sorok számának számolása

Korábban már említettem az END szabályt. Íme egy másik lehetséges alkalmazás a fájlban lévő nem üres sorok számának megszámlálására:

awk '/./ { COUNT+=1 } END { print COUNT }' file
9

Itt a COUNT változót használtam, és növeltem (+=1) minden olyan sorhoz, amely megfelel a /./ reguláris kifejezésnek. Ez azt jelenti, hogy minden sor legalább egy karaktert tartalmaz. Végül az END blokk a végeredmény megjelenítésére szolgál, miután a teljes fájl feldolgozása megtörtént. A COUNT névben nincs semmi különös. Használhattam volna a Count, count, n, xxxx vagy bármilyen más olyan nevet, amely megfelel az AWK változó elnevezési szabályainak

Azonban ez az eredmény helyes? Nos, ez az „üres” sor definíciójától függ. Ha úgy gondolja, hogy csak az üres sorok (a POSIX szerint) üresek, akkor ez helyes. De talán szívesebben tekintené üresnek a csak szóközt tartalmazó sorokat?

awk 'NF { COUNT+=1 } END { print COUNT }' file
8

Ezúttal más az eredmény, mert a későbbi verzió figyelmen kívül hagyja a csak szóközt tartalmazó sorokat, míg az eredeti verzió csak az üres sorokat. Látod a különbséget? Hagytam, hogy ezt egyedül kitaláld. Ne habozzon használni a megjegyzés részt, ha ez nem elég egyértelmű!

Végül, ha csak az adatsorok érdekelnek, és az adott bemeneti adatfájlomra tekintettel, ezt írhatnám helyette:

awk '+$1 { COUNT+=1 } END { print COUNT }' file
7

Az AWK típusú konverziós szabályok miatt működik. Az unáris plusz a mintában 1 dollár numerikus összefüggésben történő értékelését kényszeríti ki. A fájlomban az adatrekordok első mezőjében egy szám szerepel. A nem adatrekordok (címsor, üres sorok, csak szóközt tartalmazó sorok) szöveget vagy semmit sem tartalmaznak. Számokká konvertálva mindegyik egyenlő 0-val.

Vegye figyelembe, hogy ezzel a legújabb megoldással a 0 kredittel rendelkező felhasználó rekordja is elvetődik.

B. Tömbök használata AWK-ban

A tömbök az AWK erőteljes funkciói. Az AWK összes tömbje asszociatív tömb, így lehetővé teszi egy tetszőleges karakterlánc társítását egy másik értékkel. Ha ismeri a többi programozási nyelvet, akkor kivonatként, asszociatív táblázatként, ismerheti őket. szótárak vagy térképek.

9. Egy egyszerű példa az AWK tömbre

Képzeljük el, hogy tudni szeretném az összes felhasználó teljes jóváírását. Tárolhatok egy bejegyzést minden felhasználóhoz egy asszociatív tömbben, és minden alkalommal, amikor az adott felhasználó rekordjával találkozom, növelem a tömbben tárolt megfelelő értéket.

awk '+$1 { CREDITS[$3]+=$1 }
     END { for (NAME in CREDITS) print NAME, CREDITS[NAME] }' FS=, file
abhishek 17
sonia 129
öle 8
sylvain 109

Elismerem, ez már nem egysoros. Leginkább a for ciklus miatt, amely a tömb tartalmának megjelenítésére szolgál a fájl feldolgozása után. Tehát térjünk vissza a rövidebb példákhoz:

10. Ismétlődő sorok azonosítása AWK segítségével

A tömbök, csakúgy, mint a többi AWK változó, mind akcióblokkban, mind mintákban használhatók. Ennek előnyeit kihasználva egysoros szöveget írhatunk, amely csak duplikált sorokat nyomtat:

awk 'a[$0]++' file
52,01    dec   2018,sonia,team

A ++ operátor a növekmény utáni operátor, amelyet a C nyelvcsaládból örököltek (amelynek az AWK büszke tagja, köszönhetően annak, hogy Brian Kernighan volt az egyik eredeti szerzője).

Ahogy a neve is sugallja, a növekedés utáni operátor növeli („add 1”) egy változót, de csak azután, hogy az értékét felvették az englobing kifejezés kiértékeléséhez.

Ebben az esetben az a[$0] kiértékeli, hogy a rekord kinyomtatásra kerül-e vagy sem, és a döntés meghozatala után minden esetben megnövekszik a tömbbejegyzés.

Tehát a rekord első beolvasásakor az a[$0] definiálatlan, így az AWK esetében nullával egyenértékű. Tehát az első rekord nem íródik a kimenetre. Ezután ez a bejegyzés nulláról egyre változik.
Amikor másodszor is beolvassa ugyanazt a bemeneti rekordot, az a[$0] most 1. Ez „igaz”. A sor ki lesz nyomtatva. Előtte azonban a tömbbejegyzés 1-ről 2-re frissül. És így tovább.

11. Ismétlődő sorok eltávolítása

Az előző egysoros következményeként érdemes lehet eltávolítani az ismétlődő sorokat:

awk '!a[$0]++' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support


17,05 apr 2019,abhishek,guest

Az egyetlen különbség a logikai, nem pedig az operátor (!) használata, amely megfordítja a kifejezés igazságértékét. Ami hamis volt, igazzá válik, és ami igaz, az hamissá válik. A logikai nem egyáltalán nem befolyásolja a ++ utáni növekményt, amely pontosan úgy működik, mint korábban.

C. Mező- és rekordelválasztó varázslat

12. A mezőelválasztók cseréje

awk '$1=$1' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support

17;05 apr 2019;abhishek;guest

Ez a program úgy állítja be az FS és az OFS változót, hogy kómát használjon bemeneti mező elválasztóként, pontosvesszőt pedig kimeneti mező elválasztóként. Mivel az AWK mindaddig nem változtatja meg a kimeneti rekordot, amíg Ön nem változtatta meg a mezőt, a $1=$1 trükk arra kényszeríti az AWK-t, hogy megdöntse a rekordot, és újra összeállítsa a kimeneti mező elválasztó segítségével.

Ne feledje, hogy az alapértelmezett műveletblokk a { print }. Tehát átírhatnád ezt pontosabban így:

awk '$1=$1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support

17;05 apr 2019;abhishek;guest

Talán észrevette, hogy mindkét példa eltávolítja az üres sorokat. Miért? Nos, ne feledje az AWK konverziós szabályait: egy üres karakterlánc „hamis. ” Az összes többi karakterlánc „igaz. ” A $1=$1 kifejezés olyan hatás, amely megváltoztatja a $1 elemet. Azonban ez is egy kifejezés. És kiértékeli a $1 értékét – ami „false” az üres karakterlánc esetében. Ha valóban minden sort akarsz, akkor lehet, hogy valami ilyesmit kell írnod helyette:

awk '($1=$1) || 1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support



17;05 apr 2019;abhishek;guest

Emlékszel a && operátorra? Ez volt a logikus ÉS. A || a logikai VAGY. A zárójelre itt az operátorok elsőbbségi szabályai miatt van szükség. Nélkülük a minta hibásan $1=($1 || 1)ként lett volna értelmezve. Gyakorlatként hagytam, hogy tesztelje, miben lett volna akkor más az eredmény.

Végezetül, ha nem vagy túl lelkes az aritmetikában, akkor lefogadom, hogy az egyszerűbb megoldást választod:

awk '{ $1=$1; print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support



17;05 apr 2019;abhishek;guest

13. Több szóköz eltávolítása

awk '$1=$1' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest

Ez majdnem ugyanaz a program, mint az előző. A mezőelválasztókat azonban az alapértelmezett értékekre hagytam. Tehát több szóközt használunk beviteli mező elválasztóként, de csak egy szóközt használunk kimeneti mező elválasztóként. Ennek megvan az a jó mellékhatása, hogy a többszörös szóközöket egy szóközzel egyesíti.

14. Vonalak összekapcsolása AWK segítségével

Már használtuk az OFS kimeneti mező elválasztót. Amint azt már sejtette, az ORS megfelelője a kimeneti rekordelválasztó megadásához:

awk '{ print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle    abhishek

Itt minden rekord után szóközt használtam újsor karakter helyett. Ez az egybélés bizonyos esetekben elegendő, de még mindig vannak hátrányai.

A legnyilvánvalóbb, hogy nem veti el a csak szóközöket tartalmazó sorokat (az öle utáni extra szóközök ebből származnak). Tehát előfordulhat, hogy egy egyszerű reguláris kifejezést használok helyette:

awk '/[^[:space:]]/ { print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle abhishek

Most már jobb, de még mindig van egy lehetséges probléma. Nyilvánvalóbb lesz, ha az elválasztót valami láthatóra változtatjuk:

awk '/[^[:space:]]/ { print $3 }' FS=, ORS='+' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek+

A sor végén egy extra elválasztó található, mivel a mezőelválasztó minden rekord után van írva. Az utolsót is beleértve.

Ennek javítása érdekében átírom a programot úgy, hogy a második kimeneti rekordtól kezdve egy egyéni elválasztót jelenítsen meg a rekord előtt.

awk '/[^[:space:]]/ { print SEP $3; SEP="+" }' FS=, ORS='' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek

Mivel az elválasztó hozzáadásáról magam gondoskodom, a szabványos AWK kimeneti rekordelválasztót is az üres karakterláncra állítottam. Azonban amikor elkezd foglalkozni az elválasztókkal vagy a formázással, ez lehet az a jel, amelyet érdemes megfontolni a printf függvény használatával a print utasítás helyett. Ahogy most látni fogjuk.

D. Mező formázása

Már említettem az AWK és a C programozási nyelvek kapcsolatát. Többek között a C nyelvű szabványkönyvtárból az AWK örökölte a hatékony printf funkciót, amely lehetővé teszi a kimenetre küldött szöveg formázásának nagyszerű szabályozását.

A printf függvény egy formátumot vesz fel első argumentumként, amely mind a szó szerint kiadandó egyszerű szöveget, mind a kimenet különböző szakaszainak formázására használt helyettesítő karaktereket tartalmaz. A helyettesítő karaktereket a % karakter azonosítja. A leggyakoribbak a %s (karakterlánc formázásához), a %d (egész számok formázásához) és a %f (lebegőpontos számok formázásához) ). Mivel ez meglehetősen elvont lehet, lássunk egy példát:

awk '+$1 { printf("%s ",  $3) }' FS=, file; echo
sylvain sonia sonia sonia sylvain öle abhishek

Észreveheti, hogy a print utasítás ellentéteként a printf függvény nem használja az OFS és az ORS függvényeket. értékeket. Tehát, ha elválasztót szeretne, akkor ezt kifejezetten meg kell említenie, ahogy én tettem egy szóköz karakter hozzáadásával a formátum karakterláncának végén. Ezt az árat kell fizetni a kimenet teljes ellenőrzéséért.

Noha egyáltalán nem formátummeghatározó, ez kiváló alkalom a \n jelölés bevezetésére, amely bármely AWK karakterláncban használható újsor karakterek megjelenítésére.

awk '+$1 { printf("%s\n",  $3) }' FS=, file
sylvain
sonia
sonia
sonia
sylvain
öle
abhishek

15. Táblázatos eredmények előállítása

Az AWK egy rekord/mező adatformátumot kényszerít ki határolók alapján. A printf függvény használatával azonban fix szélességű táblázatos kimenetet is készíthet. Mivel a printf utasításban minden formátumspecifikátor elfogadhat egy opcionális szélességi paramétert:

awk '+$1 { printf("%10s | %4d\n",  $3, $1) }' FS=, file
   sylvain |   99
     sonia |   52
     sonia |   52
     sonia |   25
   sylvain |   10
       öle |    8
  abhishek |   17

Amint látható, az egyes mezők szélességének megadásával az AWK szóközökkel balra párnázza őket. Szövegnél általában előnyösebb a jobb oldali párnázás, amit negatív szélességszámmal lehet elérni. Egész számok esetén a mezőket szóközök helyett nullákkal tölthetjük be. Ezt úgy kaphatja meg, hogy egy explicit 0-t használ a mező szélessége előtt:

awk '+$1 { printf("%-10s | %04d\n",  $3, $1) }' FS=, file
sylvain    | 0099
sonia      | 0052
sonia      | 0052
sonia      | 0025
sylvain    | 0010
öle        | 0008
abhishek   | 0017

16. Lebegőpontos számok kezelése

A %f formátum nem érdemel sok magyarázatot…

awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%f",SUM/NUM); }' FS=, file
AVG=37.571429

… kivéve talán azt, hogy szinte mindig explicit módon szeretné beállítani a megjelenített eredmény mezőszélességét és pontosságát:

awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%6.1f",SUM/NUM); }' FS=, file
AVG=  37.6

Itt a mező szélessége 6, ami azt jelenti, hogy a mező 6 karakteres helyet foglal el (beleértve a pontot is, és végül a szokásos módon szóközökkel töltik ki a bal oldalon). A 0,1-es pontosság azt jelenti, hogy a számot a pont után 1 tizedes számmal szeretnénk megjeleníteni. Hagyom, hogy kitalálja, mit jelenítene meg helyette a %06.1.

E. Stringfüggvények használata AWK-ban

A printf függvényen kívül az AWK néhány további szép karakterlánc-manipulációs függvényt tartalmaz. Ezen a területen a modern megvalósítások, mint például a Gawk, a belső funkciók gazdagabb készletével rendelkeznek, alacsonyabb hordozhatóság árán. Ami magamat illeti, itt maradok néhány POSIX által meghatározott funkciónál, amelyeknek bárhol ugyanúgy kell működniük.

17. Szöveg átalakítása nagybetűssé

Ezt nagyon sokat használom, mert szépen kezeli a nemzetköziesedési kérdéseket:

awk '$3 { print toupper($0); }' file
99,01 JUN 2018,SYLVAIN,TEAM:::ADMIN
52,01    DEC   2018,SONIA,TEAM
52,01    DEC   2018,SONIA,TEAM
25,01    JAN   2019,SONIA,TEAM
10,01 JAN 2019,SYLVAIN,TEAM:::ADMIN
8,12    JUN   2018,ÖLE,TEAM:SUPPORT
17,05 APR 2019,ABHISHEK,GUEST

Ami azt illeti, valószínűleg ez a legjobb és leginkább hordozható megoldás a szöveg nagybetűssé alakítására a héjból.

18. Egy karakterlánc részének megváltoztatása

A substr paranccsal feloszthat egy adott hosszúságú karaktersorozatot. Itt csak a harmadik mező első karakterét használom nagybetűvel:

awk '{ $3 = toupper(substr($3,1,1)) substr($3,2) } $3' FS=, OFS=, file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,Sylvain,team:::admin
52,01    dec   2018,Sonia,team
52,01    dec   2018,Sonia,team
25,01    jan   2019,Sonia,team
10,01 jan 2019,Sylvain,team:::admin
8,12    jun   2018,Öle,team:support
17,05 apr 2019,Abhishek,guest

A substr függvény veszi a kezdeti karakterláncot, az első kivonandó karakter (1-alapú) indexét és a kibontandó karakterek számát. Ha az utolsó argumentum hiányzik, a substr a karakterlánc összes fennmaradó karakterét veszi.

Tehát a substr($3,1,1) a $3 első karakterére, a substr($3,2) pedig a maradékra azok.

19. Mezők felosztása almezőkben

Az AWK rekordmező adatmodell nagyon szép. Néha azonban a mezőket több részre szeretné osztani valamilyen belső elválasztó alapján:

awk '+$1 { split($2, DATE, " "); print $1,$3, DATE[2], DATE[3] }' FS=, OFS=, file
99,sylvain,jun,2018
52,sonia,dec,2018
52,sonia,dec,2018
25,sonia,jan,2019
10,sylvain,jan,2019
8,öle,jun,2018
17,abhishek,apr,2019

Némileg meglepő módon ez akkor is működik, ha néhány mezőmet egynél több szóköz választja el. Leginkább történelmi okokból, amikor az elválasztó egyetlen szóköz, a split figyelembe veszi, hogy „az elemeket szóközök választják el egymástól. ” És nem csak egy. Az FS speciális változó ugyanezt a konvenciót követi.

Általános esetben azonban egy karakterlánc egy karakterhez egyezik. Tehát, ha valami bonyolultabbra van szüksége, ne feledje, hogy a mezőelválasztó egy kiterjesztett reguláris kifejezés.

Példaként nézzük meg, hogyan kell kezelni a csoportmezőt, amely többértékű mezőnek tűnik, kettőspontot használva elválasztóként:

awk '+$1 { split($4, GRP, ":"); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team
sonia team
sonia team
sonia team
sylvain team
öle team support
abhishek guest

Míg azt vártam volna, hogy felhasználónként legfeljebb két csoportot jelenítsen meg, a legtöbbnél csak egyet jelenít meg. Ezt a problémát az elválasztó többszörös előfordulása okozza. Tehát a megoldás:

awk '+$1 { split($4, GRP, /:+/); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team admin
sonia team
sonia team
sonia team
sylvain team admin
öle team support
abhishek guest

Az idézőjelek helyett a perjelek a literált reguláris kifejezésként jelölik, nem pedig egyszerű karakterláncot, és a pluszjel azt jelzi, hogy ez a kifejezés megegyezik az előző karakter egy vagy több előfordulásával. Tehát ebben az esetben minden elválasztó (a leghosszabb sorozatból) egy vagy több egymást követő kettőspontból áll.

20. Keresés és csere AWK parancsokkal

Ha már a reguláris kifejezésekről beszélünk, néha olyan helyettesítést szeretne végrehajtani, mint a sed s///g parancs, de csak egy mezőn. Ebben az esetben a gsub parancsra van szüksége:

awk '+$1 { gsub(/ +/, "-", $2); print }' FS=, file
99 01-jun-2018 sylvain team:::admin
52 01-dec-2018 sonia team
52 01-dec-2018 sonia team
25 01-jan-2019 sonia team
10 01-jan-2019 sylvain team:::admin
8 12-jun-2018 öle team:support
17 05-apr-2019 abhishek guest

A gsub függvény egy reguláris kifejezést használ a kereséshez, egy helyettesítő karakterláncot és a módosítandó szöveget tartalmazó változót a helyére. Ha ez később hiányzik, akkor a rendszer 0 dollárt feltételez.

F. Munka külső parancsokkal az AWK-ban

Az AWK másik nagyszerű tulajdonsága, hogy könnyen meghívhat külső parancsokat az adatok feldolgozásához. Alapvetően kétféleképpen lehet ezt megtenni: a system utasítás használatával meghívni egy programot, és hagyni, hogy a kimenet keveredjen az AWK kimeneti folyamban. Vagy egy cső használata, hogy az AWK rögzítse a külső program kimenetét az eredmény finomabb szabályozása érdekében.

Ezek önmagukban is hatalmas témák lehetnek, de íme néhány egyszerű példa, hogy megmutassa a funkciók mögött rejlő erőt.

21. Dátum hozzáadása a fájl tetejére

awk 'BEGIN { printf("UPDATED: "); system("date") } /^UPDATED:/ { next } 1' file
UPDATED: Thu Feb 15 00:31:03 CET 2018
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

Abban az AWK programban kezdem a FRISSÍTETT munka megjelenítésével. Ezután a program meghívja a külső dátum parancsot, amely közvetlenül az AWK által abban a szakaszban előállított szöveg után küldi el eredményét a kimeneten.
Az AWK program többi része csak eltávolít egy frissítési utasítást, amely végül megtalálható a fájlban, és kinyomtatja az összeset. a többi sor (az 1 szabállyal).

Figyelje meg a next utasítást. Az aktuális rekord feldolgozásának megszakítására szolgál. Ez egy szabványos módja a bemeneti fájl egyes rekordjainak figyelmen kívül hagyásának.

22. Mező módosítása külsőleg

Bonyolultabb esetekben előfordulhat, hogy figyelembe kell vennie a | getline VARIABLE AWK idióma:

awk '+$1 { CMD | getline $5; close(CMD); print }' CMD="uuid -v4" FS=, OFS=, file
99,01 jun 2018,sylvain,team:::admin,5e5a1bb5-8a47-48ee-b373-16dc8975f725
52,01    dec   2018,sonia,team,2b87e9b9-3e75-4888-bdb8-26a9b34facf3
52,01    dec   2018,sonia,team,a5fc22b5-5388-49be-ac7b-78063cbbe652
25,01    jan   2019,sonia,team,3abb0432-65ef-4916-9702-a6095f3fafe4
10,01 jan 2019,sylvain,team:::admin,592e9e80-b86a-4833-9e58-1fe2428aa2a2
8,12    jun   2018,öle,team:support,3290bdef-fd84-4026-a02c-46338afd4243
17,05 apr 2019,abhishek,guest,e213d756-ac7f-4228-818f-1125cba0810f

Ez lefuttatja a CMD változóban tárolt parancsot, beolvassa a parancs kimenetének első sorát, és eltárolja a $5 változóban.

Különös figyelmet kell fordítani a close utasításra, ami itt kulcsfontosságú, mivel azt szeretnénk, hogy az AWK a külső parancs új példányát hozza létre minden alkalommal, amikor végrehajtja a CMD | getline utasítást. A close utasítás nélkül az AWK ehelyett több sort próbálna beolvasni ugyanabból a parancspéldányból.

23. Dinamikusan generált parancsok meghívása

Az AWK parancsai csak sima karakterláncok, semmi különös nélkül. A pipe operátor indítja el a külső programok végrehajtását. Tehát, ha szükséges, dinamikusan szerkeszthet tetszőleges összetett parancsokat az AWK karakterlánc-manipulációs függvények és operátorok használatával.

awk '+$1 { cmd = sprintf(FMT, $2); cmd | getline $2; close(cmd); print }' FMT='date -I -d "%s"'  FS=, file
99 2018-06-01 sylvain team:::admin
52 2018-12-01 sonia team
52 2018-12-01 sonia team
25 2019-01-01 sonia team
10 2019-01-01 sylvain team:::admin
8 2018-06-12 öle team:support
17 2019-04-05 abhishek guest

A printf függvénnyel már találkoztunk. A sprintf nagyon hasonló, de visszaadja a beépített karakterláncot, nem pedig a kimenetre küldi.

24. Adatok összekapcsolása

Hogy megmutassam a szoros kijelentés célját, engedtem, hogy próbálja ki az utolsó példát:

awk '+$1 { CMD | getline $5; print }' CMD='od -vAn -w4 -t x /dev/urandom' FS=, file
99 01 jun 2018 sylvain team:::admin  1e2a4f52
52 01    dec   2018 sonia team  c23d4b65
52 01    dec   2018 sonia team  347489e5
25 01    jan   2019 sonia team  ba985e55
10 01 jan 2019 sylvain team:::admin  81e9a01c
8 12    jun   2018 öle team:support  4535ba30
17 05 apr 2019 abhishek guest  80a60ec8

A fenti uuid parancsot használó példa ellentéteként itt csak egy az od példány indul el, miközben az AWK program fut, és az egyes rekordok feldolgozása során még egy sort olvasunk az ugyanaz folyamat kimenetéből.

Következtetés

Az AWK gyors bemutatója biztosan nem helyettesítheti az eszköz teljes értékű tanfolyamát vagy oktatóanyagát. Azonban azoknak, akik nem ismerték, remélem, elég ötletet adott ahhoz, hogy azonnal hozzáadhassa az AWK-t az eszköztárához.

Másrészt, ha már az AWK rajongója volt, itt találhat néhány trükköt, amellyel hatékonyabb lehet, vagy egyszerűen lenyűgözheti barátait.

Azonban nem teszek úgy, mintha a teljesség igénye volna. Tehát minden esetben ne habozzon megosztani kedvenc AWK one-linerjét vagy bármely más AWK tippet az alábbi megjegyzés rovat segítségével!

Kapcsolódó cikkek: