Come utilizzare il linguaggio AWK per manipolare il testo in Linux

Introduzione

Le utility Linux spesso seguono la filosofia di progettazione di Unix. Si incoraggia l’uso di strumenti piccoli, utilizzare file di testo semplici per l’input e l’output, e operare in modo modulare. Grazie a questa eredità, abbiamo ottime funzionalità di elaborazione del testo con strumenti come sed e awk.

awk è sia un linguaggio di programmazione che un elaboratore di testo che puoi utilizzare per manipolare dati di testo in modi molto utili. In questa guida, esplorerai come utilizzare lo strumento da riga di comando awk e come utilizzarlo per elaborare il testo.

Sintassi di base

Il comando awk è incluso per impostazione predefinita in tutti i moderni sistemi Linux, quindi non è necessario installarlo per iniziare a usarlo.

awk è più utile quando si manipolano file di testo formattati in modo prevedibile. Ad esempio, è eccellente nel parsing e nella manipolazione di dati tabulari. Opera su base riga per riga e itera attraverso l’intero file.

Per impostazione predefinita, utilizza gli spazi bianchi (spazi, tabulazioni, ecc.) per separare i campi. Fortunatamente, molti file di configurazione sul tuo sistema Linux utilizzano questo formato.

Il formato di base di un comando awk è:

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

Puoi omettere la parte di ricerca o la parte di azione da qualsiasi comando awk. Per default, l’azione intrapresa se la parte “azione” non è fornita è “stampare”. Questo stampa semplicemente tutte le righe che corrispondono.

Se la parte di ricerca non è fornita, awk esegue l’azione elencata su ogni riga.

Se entrambe sono fornite, awk utilizza la parte di ricerca per decidere se la riga corrente riflette il modello, e poi esegue le azioni sulle corrispondenze.

Nella sua forma più semplice, puoi utilizzare awk come cat per stampare tutte le righe di un file di testo sullo schermo.

Crea un file favorite_food.txt che elenca i cibi preferiti di un gruppo di amici:

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

Ora utilizza il comando awk per stampare il file sullo schermo:

  1. awk '{print}' favorite_food.txt

Vedrai il file stampato sullo schermo:

Output
carrot sandy wasabi luke sandwich brian salad ryan spaghetti jessica

Questo non è molto utile. Proviamo le capacità di filtraggio della ricerca di awk cercando nel file il testo “sand”:

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

Come puoi vedere, awk stampa ora solo le righe che contengono i caratteri “sand”.

Utilizzando le espressioni regolari, puoi mirare a parti specifiche del testo. Per visualizzare solo la riga che inizia con le lettere “sand”, utilizza l’espressione regolare ^sand:

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

Questa volta, viene visualizzata solo una riga:

Output
sandwich brian

Allo stesso modo, puoi utilizzare la sezione di azione per specificare quali informazioni vuoi stampare. Ad esempio, per stampare solo la prima colonna, utilizza il seguente comando:

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

Puoi fare riferimento ad ogni colonna (delimitata da spazi) tramite variabili associate al numero della colonna. Ad esempio, la prima colonna è $1, la seconda è $2, e puoi fare riferimento all’intera riga con $0.

Variabili Interne e Formato Espanso

Il comando awk utilizza alcune variabili interne per assegnare determinate informazioni mentre elabora un file.

Le variabili interne utilizzate da awk sono:

  • FILENAME: Fa riferimento al file di input corrente.
  • FNR: Fa riferimento al numero del record corrente relativo al file di input corrente. Ad esempio, se hai due file di input, questo ti direbbe il numero di record di ciascun file invece che in totale.
  • FS: Il separatore di campo corrente utilizzato per indicare ogni campo in un record. Per impostazione predefinita, questo è impostato su spazio bianco.
  • NF: Il numero di campi nel record corrente.
  • NR: Il numero del record corrente.
  • OFS: Il separatore di campo per i dati in output. Per impostazione predefinita, questo è impostato su spazio bianco.
  • ORS: Il separatore di record per i dati in output. Per impostazione predefinita, questo è un carattere di nuova riga.
  • RS: Il separatore di record utilizzato per distinguere i record separati nel file di input. Per default, questo è un carattere di nuova riga.

Puoi cambiare i valori di queste variabili a tuo piacimento per adattarle alle esigenze dei tuoi file. Di solito lo fai durante la fase di inizializzazione del tuo elaborato.

Questo ci porta a un altro concetto importante. La sintassi di awk è leggermente più complessa rispetto a quanto hai usato finora. Ci sono anche blocchi BEGIN e END opzionali che possono contenere comandi da eseguire prima e dopo l’elaborazione del file, rispettivamente.

Questo fa sì che la nostra sintassi espansa assomigli a qualcosa del genere:

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

I parole chiave BEGIN e END sono insiemi specifici di condizioni, proprio come i parametri di ricerca. Si abbinano prima e dopo che il documento sia stato elaborato.

Questo significa che puoi cambiare alcune delle variabili interne nella sezione BEGIN. Ad esempio, il file /etc/passwd è delimitato da due punti (:) invece di spazi bianchi.

Per stampare la prima colonna di questo file, esegui il seguente comando:

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

Puoi utilizzare i blocchi BEGIN e END per stampare informazioni sui campi che stai stampando. Usa il seguente comando per trasformare i dati dal file in una tabella, ben spaziata con tabulazioni utilizzando \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

Vedrai questo output:

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

Come puoi vedere, puoi formattare le cose abbastanza bene sfruttando alcune delle funzionalità di awk.

Ogni sezione espansa è facoltativa. In realtà, la sezione di azione principale stessa è facoltativa se è definita un’altra sezione. Ad esempio, puoi fare cose del genere:

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

E vedrai questo output:

Output
We can use awk like the echo command

Ora vediamo come cercare il testo all’interno dei campi dell’output.

Ricerca dei campi ed espressioni composte

In uno degli esempi precedenti, hai stampato la riga nel file favorite_food.txt che iniziava con “sand”. Questo è stato facile perché stavi cercando l’inizio dell’intera riga.

Cosa succede se vuoi scoprire se un modello di ricerca corrisponde all’inizio di un campo invece?

Crea una nuova versione del file favorite_food.txt che aggiunga un numero di elemento di fronte al cibo di ogni persona:

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

Se vuoi trovare tutti i cibi da questo file che iniziano con “sa”, potresti cominciare provando qualcosa del genere:

  1. awk '/sa/' favorite_food.txt

Questo mostra tutte le righe che contengono “sa”:

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

In questo caso, stai cercando corrispondenze con qualsiasi istanza di “sa” nella parola. Questo finisce per includere cose come “wasabi” che hanno il modello in mezzo, o “sandy” che non è nella colonna desiderata. In questo caso sei interessato solo alle parole che iniziano con “sa” nella seconda colonna.

Puoi dire ad awk di corrispondere solo all’inizio della seconda colonna utilizzando questo comando:

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

Come puoi vedere, questo ci consente di cercare solo all’inizio della seconda colonna per una corrispondenza.

La parte field_num ~ specifica che awk dovrebbe prestare attenzione solo alla seconda colonna.

Output
3 sandwich brian 4 salad ryan

Puoi facilmente cercare anche le cose che non corrispondono includendo il carattere “!” prima del tilde (~). Questo comando restituirà tutte le righe che non hanno un cibo che inizia con “sa”:

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

Se decidi in seguito che sei interessato solo alle righe che non iniziano con “sa” e il numero dell’articolo è inferiore a 5, potresti utilizzare un’espressione composta come questa:

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

Questo introduce alcuni nuovi concetti. Il primo è la possibilità di aggiungere ulteriori requisiti affinché la riga corrisponda utilizzando l’operatore &&. Utilizzando questo, puoi combinare un numero arbitrario di condizioni affinché la riga corrisponda. In questo caso, stai utilizzando questo operatore per aggiungere un controllo che il valore della prima colonna sia inferiore a 5.

Vedrai questo output:

Output
1 carrot sandy 2 wasabi luke

Puoi utilizzare awk per elaborare i file, ma puoi anche lavorare con l’output di altri programmi.

Elaborazione dell’Output di Altri Programmi

Puoi utilizzare il comando awk per analizzare l’output di altri programmi anziché specificare un nome file. Ad esempio, puoi utilizzare awk per estrarre l’indirizzo IPv4 dal comando ip.

Il comando ip a visualizza l’indirizzo IP, l’indirizzo di broadcast e altre informazioni su tutte le interfacce di rete sulla tua macchina. Per visualizzare le informazioni per l’interfaccia chiamata eth0, usa questo comando:

  1. ip a s eth0

Vedrai i seguenti risultati:

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

Puoi utilizzare awk per individuare la linea inet e quindi stampare solo l’indirizzo IP:

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

Il flag -F dice a awk di delimitare mediante barre oblique in avanti o spazi utilizzando l’espressione regolare [\/ ]+. Ciò divide la linea inet 172.17.0.11/16 in campi separati. L’indirizzo IP è nel terzo campo perché gli spazi all’inizio della linea contano anche come un campo, poiché hai delimitato tramite spazi oltre che barre oblique. Nota che awk ha trattato gli spazi consecutivi come un singolo spazio in questo caso.

L’output mostra l’indirizzo IP:

Output
172.17.0.11

Troverai molti casi in cui puoi utilizzare awk per cercare o analizzare l’output di altri comandi.

Conclusione

Ormai dovresti avere una comprensione di base di come puoi utilizzare il comando awk per manipolare, formattare e stampare selettivamente file di testo e flussi di testo. Awk è un argomento molto più ampio, tuttavia, ed è effettivamente un intero linguaggio di programmazione completo di assegnazione di variabili, strutture di controllo, funzioni integrate e altro ancora. Puoi usarlo all’interno dei tuoi script per formattare il testo in modo affidabile.

Per saperne di più su awk, puoi leggere il libro di pubblico dominio gratuito dei suoi creatori che approfondisce molto di più.

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