Hoe de AWK-taal te gebruiken om tekst te manipuleren in Linux

Inleiding

Linux-hulpprogramma’s volgen vaak de Unix-filosofie van ontwerp. Tools worden aangemoedigd om klein te zijn, platte tekstbestanden te gebruiken voor invoer en uitvoer, en modulair te werken. Vanwege deze erfenis hebben we geweldige functionaliteit voor tekstverwerking met tools zoals sed en awk.

awk is zowel een programmeertaal als een tekstverwerker die je kunt gebruiken om tekstgegevens op zeer nuttige manieren te manipuleren. In deze gids zul je ontdekken hoe je de awk opdrachtregeltool kunt gebruiken en hoe je deze kunt gebruiken om tekst te verwerken.

Basis syntaxis

De awk opdracht is standaard inbegrepen in alle moderne Linux-systemen, dus je hoeft het niet te installeren om ermee te beginnen.

awk is het meest nuttig bij het omgaan met tekstbestanden die op een voorspelbare manier zijn opgemaakt. Het is bijvoorbeeld uitstekend in het parseren en manipuleren van tabulaire gegevens. Het werkt op regel-voor-regelbasis en doorloopt het hele bestand.

Standaard gebruikt het witruimte (spaties, tabs, enz.) om velden te scheiden. Gelukkig gebruiken veel configuratiebestanden op je Linux-systeem dit formaat.

De basisindeling van een awk-opdracht is:

  1. awk '/search_pattern/ { action_to_take_on_matches; another_action; }' file_to_parse

Je kunt ofwel het zoekgedeelte of het actiegedeelte weglaten uit elke awk-opdracht. Standaard wordt de actie uitgevoerd als het “actie” gedeelte niet is opgegeven, is “print”. Dit drukt eenvoudig alle regels af die overeenkomen.

Als het zoekgedeelte niet is opgegeven, voert awk de vermelde actie uit op elke regel.

Als beide zijn opgegeven, gebruikt awk het zoekgedeelte om te beslissen of de huidige regel overeenkomt met het patroon, en voert vervolgens de acties uit bij overeenkomsten.

In zijn eenvoudigste vorm kun je awk gebruiken zoals cat om alle regels van een tekstbestand op het scherm af te drukken.

Maak een bestand favorite_food.txt waarin de favoriete voedingsmiddelen van een groep vrienden worden vermeld:

  1. echo "carrot sandy
  2. wasabi luke
  3. sandwich brian
  4. salad ryan
  5. spaghetti jessica" > favorite_food.txt

Gebruik nu de awk-opdracht om het bestand naar het scherm af te drukken:

  1. awk '{print}' favorite_food.txt

Je ziet dat het bestand naar het scherm wordt afgedrukt:

Output
carrot sandy wasabi luke sandwich brian salad ryan spaghetti jessica

Dit is niet erg nuttig. Laten we de zoekfiltermogelijkheden van awk uitproberen door door het bestand te zoeken naar de tekst “zand”:

  1. awk '/sand/' favorite_food.txt
Output
carrot sandy sandwich brian

Zoals je kunt zien, drukt awk nu alleen de regels af die de tekens “zand” bevatten.

Met reguliere expressies kun je specifieke delen van de tekst targeten. Om alleen de regel weer te geven die begint met de letters “zand”, gebruik je de reguliere expressie ^zand:

  1. awk '/^sand/' favorite_food.txt

Deze keer wordt slechts één regel weergegeven:

Output
sandwich brian

Vergelijkbaar, je kunt het actieg gedeelte gebruiken om aan te geven welke informatie je wilt afdrukken. Bijvoorbeeld, om alleen de eerste kolom af te drukken, gebruik je de volgende opdracht:

  1. awk '/^sand/ {print $1;}' favorite_food.txt
Output
sandwich

U kunt elke kolom (zoals aangegeven door witruimte-delimiters) verwijzen met variabelen die zijn geassocieerd met hun kolomnummer. Bijvoorbeeld, de eerste kolom is $1, de tweede is $2, en u kunt de hele regel refereren met $0.

Interne Variabelen en Uitgebreid Formaat

De awk-opdracht gebruikt enkele interne variabelen om bepaalde stukken informatie toe te wijzen terwijl het een bestand verwerkt.

De interne variabelen die awk gebruikt zijn:

  • FILENAME: Verwijst naar het huidige invoerbestand.
  • FNR: Verwijst naar het nummer van het huidige record ten opzichte van het huidige invoerbestand. Bijvoorbeeld, als u twee invoerbestanden heeft, zou dit u het recordnummer van elk bestand vertellen in plaats van als totaal.
  • FS: De huidige veldscheider die wordt gebruikt om elk veld in een record aan te duiden. Standaard is dit ingesteld op witruimte.
  • NF: Het aantal velden in het huidige record.
  • NR: Het nummer van het huidige record.
  • OFS: De veldscheider voor de uitvoergegevens. Standaard is dit ingesteld op witruimte.
  • ORS: De recordscheider voor de uitvoergegevens. Standaard is dit een nieuwregelkarakter.
  • RS: Het recordseparator wordt gebruikt om afzonderlijke records in het invoerbestand te onderscheiden. Standaard is dit een newline-teken.

U kunt de waarden van deze variabelen naar wens wijzigen om aan de behoeften van uw bestanden te voldoen. Meestal doet u dit tijdens de initialisatiefase van uw verwerking.

Dit brengt ons bij een ander belangrijk concept. De syntaxis van awk is iets complexer dan wat je tot nu toe hebt gebruikt. Er zijn ook optionele BEGIN en END blokken die commando’s kunnen bevatten om respectievelijk vóór en na de bestandsverwerking uit te voeren.

Dit maakt onze uitgebreide syntaxis er ongeveer zo uit:

  1. awk 'BEGIN { action; }
  2. /search/ { action; }
  3. END { action; }' input_file

De BEGIN en END trefwoorden zijn specifieke reeksen voorwaarden, net als de zoekparameters. Ze komen overeen vóór en na het verwerken van het document.

Dit betekent dat u sommige interne variabelen in de BEGIN-sectie kunt wijzigen. Bijvoorbeeld, het bestand /etc/passwd is gescheiden door dubbelepunten (:) in plaats van spaties.

Om de eerste kolom van dit bestand af te drukken, voert u het volgende commando uit:

  1. awk 'BEGIN { FS=":"; }
  2. { print $1; }' /etc/passwd
Output
root daemon bin sys sync games man . . .

U kunt de BEGIN en END blokken gebruiken om informatie over de velden die u afdrukt weer te geven. Gebruik het volgende commando om de gegevens uit het bestand om te zetten in een tabel, mooi opgemaakt met tabs met behulp van \t:

  1. awk 'BEGIN { FS=":"; print "User\t\tUID\t\tGID\t\tHome\t\tShell\n--------------"; }
  2. {print $1,"\t\t",$3,"\t\t",$4,"\t\t",$6,"\t\t",$7;}
  3. END { print "---------\nFile Complete" }' /etc/passwd

U ziet deze uitvoer:

Output
User UID GID Home Shell -------------- root 0 0 /root /bin/bash daemon 1 1 /usr/sbin /bin/sh bin 2 2 /bin /bin/sh sys 3 3 /dev /bin/sh sync 4 65534 /bin /bin/sync . . . --------- File Complete

Zoals u kunt zien, kunt u dingen behoorlijk mooi formatteren door gebruik te maken van enkele functies van awk.

Elk van de uitgebreide secties is optioneel. Sterker nog, de hoofdactiesectie zelf is optioneel als er een andere sectie is gedefinieerd. Je kunt bijvoorbeeld dingen doen zoals dit:

  1. awk 'BEGIN { print "We can use awk like the echo command"; }'

En je ziet deze output:

Output
We can use awk like the echo command

Nu gaan we kijken hoe je tekst kunt zoeken binnen velden van de uitvoer.

Veldzoeken en samengestelde expressies

In een van de vorige voorbeelden heb je de regel in het bestand favorite_food.txt afgedrukt die begon met “sand”. Dit was gemakkelijk omdat je zocht naar het begin van de hele regel.

Wat als je wilt weten of een zoekpatroon overeenkomt met het begin van een veld in plaats daarvan?

Maak een nieuwe versie van het bestand favorite_food.txt waarin voor elk voedsel van een persoon een itemnummer wordt toegevoegd:

  1. echo "1 carrot sandy
  2. 2 wasabi luke
  3. 3 sandwich brian
  4. 4 salad ryan
  5. 5 spaghetti jessica" > favorite_food.txt

Als je alle voedingsmiddelen uit dit bestand wilt vinden die beginnen met “sa”, zou je iets als dit kunnen proberen:

  1. awk '/sa/' favorite_food.txt

Dit toont alle regels die “sa” bevatten:

Output
1 carrot sandy 2 wasabi luke 3 sandwich brian 4 salad ryan

Hierbij match je elke instantie van “sa” in het woord. Dit omvat uiteindelijk dingen zoals “wasabi” die het patroon in het midden hebben, of “sandy” die niet in de kolom staat die je wilt. In dit geval ben je alleen geïnteresseerd in woorden die beginnen met “sa” in de tweede kolom.

U kunt awk vertellen om alleen overeenkomsten te vinden aan het begin van de tweede kolom met behulp van deze opdracht:

  1. awk '$2 ~ /^sa/' favorite_food.txt

Zoals u kunt zien, stelt dit ons in staat om alleen te zoeken aan het begin van de tweede kolom voor een overeenkomst.

Het gedeelte field_num ~ geeft aan dat awk alleen aandacht moet besteden aan de tweede kolom.

Output
3 sandwich brian 4 salad ryan

U kunt net zo gemakkelijk zoeken naar dingen die niet overeenkomen door het “!” teken voor de tilde (~) op te nemen. Met deze opdracht worden alle regels geretourneerd die geen voedsel hebben dat begint met “sa”:

  1. awk '$2 !~ /^sa/' favorite_food.txt
Output
1 carrot sandy 2 wasabi luke 5 spaghetti jessica

Als u later besluit dat u alleen geïnteresseerd bent in regels die niet beginnen met “sa” en het itemnummer minder dan 5 is, kunt u een samengestelde expressie als deze gebruiken:

  1. awk '$2 !~ /^sa/ && $1 < 5' favorite_food.txt

Dit introduceert een paar nieuwe concepten. Het eerste is de mogelijkheid om extra vereisten toe te voegen voor de overeenkomst van de regel door de && operator te gebruiken. Hiermee kunt u een willekeurig aantal voorwaarden combineren voor de overeenkomst van de regel. In dit geval gebruikt u deze operator om een controle toe te voegen dat de waarde van de eerste kolom minder is dan 5.

U zult deze uitvoer zien:

Output
1 carrot sandy 2 wasabi luke

U kunt awk gebruiken om bestanden te verwerken, maar u kunt ook werken met de uitvoer van andere programma’s.

Verwerken van uitvoer van andere programma’s

U kunt het awk commando gebruiken om de uitvoer van andere programma’s te analyseren in plaats van een bestandsnaam op te geven. Bijvoorbeeld, u kunt awk gebruiken om het IPv4-adres uit het ip commando te halen.

Het ip a commando geeft het IP-adres, broadcastadres en andere informatie weer over alle netwerkinterfaces op uw machine. Om de informatie voor de interface genaamd eth0 weer te geven, gebruikt u dit commando:

  1. ip a s eth0

U ziet de volgende resultaten:

Output
2571: eth0@if2572: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:0b brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.11/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever

U kunt awk gebruiken om de inet regel te targeten en vervolgens alleen het IP-adres af te drukken:

  1. ip a s eth0 | awk -F '[\/ ]+' '/inet / {print $3}'

De -F vlag vertelt awk om te delen door voorwaartse slashes of spaties met de reguliere expressie [\/ ]+. Dit splitst de regel inet 172.17.0.11/16 in afzonderlijke velden. Het IP-adres bevindt zich in het derde veld omdat de spaties aan het begin van de regel ook tellen als een veld, aangezien u hebt gedeeld door spaties en slashes. Merk op dat awk opeenvolgende spaties als één spatie behandelde in dit geval.

De uitvoer toont het IP-adres:

Output
172.17.0.11

U zult veel plaatsen vinden waar u awk kunt gebruiken om te zoeken of de uitvoer van andere commando’s te analyseren.

Conclusie

Tegenwoordig zou je een basisbegrip moeten hebben van hoe je het awk-commando kunt gebruiken om tekstbestanden en tekststreams te manipuleren, formatteren en selectief af te drukken. Awk is echter een veel groter onderwerp en is eigenlijk een volledige programmeertaal met variabelentoewijzing, controlestructuren, ingebouwde functies en meer. Je kunt het binnen je eigen scripts gebruiken om tekst op een betrouwbare manier te formatteren.

Om meer te leren over awk, kun je het gratis publiek domein boek van de makers lezen, dat veel meer gedetailleerd ingaat.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-the-awk-language-to-manipulate-text-in-linux