Files
Blog/posts/10Aug-AWK_basis.md
Eli Winderickx 3606b5d8a7 Base 0
2024-03-24 14:41:41 +01:00

86 lines
5.6 KiB
Markdown

---
title: "Een AWK-basis"
excerpt: "Heel tof dat jij scripts kan schrijven. Tijd voor een versnelling hoger met AWK. Een onmisbare tool om oneliners te schrijven"
date: "2023-08-10T15:00:00.000Z"
author: Eli Winderickx
hero_image: /awk.png
category: AWK,GNU-tools,Linux,Scripting
---
## Wat eerst?
Het commando `awk` (of `gawk`) is een supersterke tool die meegeleverd wordt met de meeste `GNU/Linux` distributies en een eerste versie bestaat al sinds 1977. De `gawk` is de `GNU` implementatie van de `awk`-tool. Als je een `ls -alh $(which awk)` uitvoert, merk je dat dat een symlink is naar de `gawk` executable.
> Leuk weetje: de Naam `AWK` komt van de oorspronkelijke ontwikkelaars; Aho, Weinberger en Kernighan.
Deze tool ga je kunnen gebruiken voor tekst verwerking en manipulaties. Specifiek gaat `awk` lijnen, records of tekst zoeken die aan bepaalde patronen voldoen. De gefilterde content kunnen we dan uitvoeren met bepaalde manipulaties. `Awk` is eigenlijk ook een volledige programmeertaal waarmee je tal van functies in en buiten `awk` kan benutten voor wat je probeert te bereiken.
### De alternatieven
Velen zullen ongetwijfel ook gekend zijn met `grep` en `sed`. Beide commando's zijn ook vaak beschikbaar en alhoewel ook stevige opties, kunnen ze niet zo veel als `awk`. Leer alle commando's sowieso kennen maar als je je specialiseert in één van de drie, kies dan zeker voor `awk`. De tool `grep` is voornamelijk gekend voor eenvoudig tekst in bestanden terug te vinden. `Sed` daarnaast is een specialist als `stream editor` om tekst eenvoudig aan te passen. Hou deze blog zeker in het oog als je ook van deze tools meer wilt weten.
```bash
# Zoek recursief naar TEKST en inverteer dan de selectie
grep -v -r "TEKST" /pad/naar/map/of/bestand
# zoek naar alle TEXT entries vanaf lijn 3 in een bestand en verander naar TEKST
sed -n `3,$ s/TEXT/TEKST/g` <bestand>
```
## Belangrijk om te weten
`AWK` gebruikt een aantal automatische variabelen om je op weg te helpen. Dit zijn de voornaamste die je gaat willen gebruiken:
- RS (**R**ecord **S**eperator): Standaard gaat `AWK` lijn per lijn willen verwerken. Dit gaat in vele gevallen ook telkens een nieuwe record aangeven. Als dat niet het geval is, kan je dit aanpassen naar een andere waarde.
- NR (current input **N**umber **R**ecord): Per record dat er verwerkt wordt, wordt er ook bijgehouden op welk record nummer we zitten. Dat nummer wordt opgeslagen in het `NR`. Je kan zo de even of onevenrecords filteren of misschien alleen de eerste lijn laten vallen.
- FS/OFS ((**O**utput) **F**ield **S**eperator): Binnen een lijn of record zitten verschillende fields of data items. In een CSV-bestand worden die vaak gesplitst met een `,` of een `;`-teken. De `FS` is dan het record waarmee `AWK` de input gaat splitsen. Achteraf bij het printen van de output, kan dat opnieuw gesplitst worden met de `OFS`-variabele.
- NF (**N**umber **F**ield): Dit geeft aan hoeveel data items er in het huidige record bevinden. Dit kan handig zijn als `FS` nog steeds een standaard whitespace is. Zo weet je meteen hoeveel woorden er in het record zitten.
## Een paar commando's
Het meest basis commando is: print alle records. Dat doen we zo:
```bash
awk '1 {print}' <bestand>
# Omdat dit de default actie is, kunnen we ook
awk 1 <bestand>
```
Omdat we de standaard actie `print` kennen, kunnen we deze weglaten en een paar complexere bewerkingen typen.
```bash
# Toon alles behalve de eerste lijn / record
awk 'NR>1' <bestand>
# Toon enkel de eerste lijn / record
awk 'NR==1' <bestand>
# Toon lijn / record 2 en 3
awk 'NR>1 && NR<4' <bestand>
# Verwijder alle witlijnen
awk 'NF' <bestand>
```
We kunnen ook zoeken op tekst en die tekst aanpassen:
```bash
# Zoek naar "TEKST"
awk '/TEKST/ {print $0}' <bestand>
# Vervang TEXT naar TEKST
awk '{gsub(/TEXT/,"TEKST")}{print}' <bestand>
```
> Standaard gaat `awk` de output naar de terminal sturen. Maak daar gebruik van om jouw wijzigingen eerst te controleren. Achteraf kan je dit gemakkelijk doorsturen naar een onder bestand met `>` of `>>`. Wil je toch het originele bestand aanpassen gebruik dan `awk -i inplace`.
Wiskundige berekeningen zijn ook geen probleem. Lijnen of records tellen of de data zelf optellen? Dat doe je zo:
```bash
# Tel alle records van kolom 4 en tel dan enkel die waar waarin TEKST voorkomt
awk '{count[$4]++} END {print count["TEKST"]}' FS=, <bestand>
# Maak een som van alle waarde in de eerste kolom
awk '{ SOM=SOM+$1 } END {print SOM}' FS=; OFS=; <bestand>
# Als een waarde in de eerste kolom hoger is dan 9000, print dan die lijn
awk '{ if ($1 > 9000) {print $0} }' <bestand>
```
Met die laatste entries zie je al dat we richting een echte programmeertaal aan het gaan zijn. Nu gaan we nog een stapje verder met een `for`-lus. Als je niet vertrouwd bent met programeren, gaat deze data als een groupering of array beschouwen. Voor iedere aparte waarde, gaan we dan een bewerking doen. In dit geval optellen per naam.
```bash
awk `+$1 { CREDITS[$3]+=$1} END { for (NAAM in CREDITS) print NAAM, CREDITS[NAAM]}` FS=, <bestand>
```
Naast een `for`-lus, heb je ook `if-else` of `switch`-statements voor conditionele statements en `while`- en `do-while`-lussen voor iteratie.
Tot slot nog een ander leuk trukje is externe commando's oproepen en de output daarvan toevoegen aan jouw data. Hieronder halen we zo bijvoorbeeld de datum op door het `date`-commando uit te voeren. Dit gebruiken we om een hoofdding aan te maken om aan te geven wanneer het bestand aangepast is.
```bash
awk 'BEGIN { printf("AANGEPAST OP: "); system("date")} /^AANGEPAST OP:/ {next} 1' <bestand>
```
[De volledige `GAWK` handleiding is vrij en gratis beschikbaar op de website van GNU.org.](https://www.gnu.org/software/gawk/manual/gawk.html)