Awk è l'onnipresente comando Unix per la scansione e l'elaborazione di testo contenente schemi prevedibili. Tuttavia, poiché è dotato di funzioni, è anche giustamente chiamato linguaggio di programmazione.
Confusamente, c'è più di un awk. (Oppure, se ritieni che possa essercene solo uno, allora ci sono diversi cloni.) C'è awk , il programma originale scritto da Aho, Weinberger e Kernighan, e poi c'è nawk , fascino e la versione GNU, gawk . La versione GNU di awk è una versione software gratuita e altamente portatile dell'utilità con diverse caratteristiche uniche, quindi questo articolo riguarda GNU awk.
Sebbene il suo nome ufficiale sia gawk, sui sistemi GNU+Linux è alias di awk e funge da versione predefinita di quel comando. Su altri sistemi che non vengono forniti con GNU awk, è necessario installarlo e chiamarlo gawk, anziché awk. Questo articolo usa i termini awk e gawk in modo intercambiabile.
Essendo sia un comando che un linguaggio di programmazione, awk è un potente strumento per attività che altrimenti potrebbero essere lasciate da ordinare , taglia , unique e altre utilità comuni. Fortunatamente, c'è molto spazio nell'open source per la ridondanza, quindi se ti trovi di fronte alla domanda se usare o meno awk, la risposta è probabilmente un solido "forse".
La bellezza della flessibilità di awk è che se ti sei già impegnato a utilizzare awk per un'attività, probabilmente puoi rimanere in awk, indipendentemente da ciò che succede lungo il percorso. Ciò include l'eterna necessità di ordinare i dati in un modo diverso dall'ordine che ti è stato consegnato.
Set di campioni
Prima di esplorare i metodi di ordinamento di awk, genera un set di dati di esempio da utilizzare. Mantieni la semplicità in modo da non farti distrarre da casi limite e complessità involontaria. Questo è il set di esempio utilizzato da questo articolo:
Aptenodytes;forsteri;Miller,JF;1778;Emperor
Pygoscelis;papua;Wagler;1832;Gentoo
Eudyptula;minor;Bonaparte;1867;Little Blue
Spheniscus;demersus;Brisson;1760;African
Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
Torvaldis;linux;Ewing,L;1996;Tux
È un piccolo set di dati, ma offre una buona varietà di tipi di dati:
- Un nome di genere e specie, che sono associati tra loro ma considerati separati
- Un cognome, a volte con le iniziali dopo una virgola
- Un numero intero che rappresenta una data
- Un termine arbitrario
- Tutti i campi separati da punto e virgola
A seconda del tuo background educativo, puoi considerarlo un array 2D o una tabella o solo una raccolta di dati delimitata da righe. Come ci pensi dipende da te, perché awk non si aspetta nient'altro che testo. Sta a te dire ad awk come vuoi analizzarlo.
Il trucco di ordinamento
Se desideri semplicemente ordinare un set di dati di testo in base a un campo specifico e definibile (pensa a una "cella" in un foglio di calcolo), puoi utilizzare il comando di ordinamento.
Campi e record
Indipendentemente dal formato del tuo input, devi trovare dei modelli in esso in modo da poterti concentrare sulle parti dei dati che sono importanti per te. In questo esempio, i dati sono delimitati da due fattori:righe e campi. Ogni nuova riga rappresenta un nuovo record , come probabilmente vedresti in un foglio di calcolo o in un dump del database. All'interno di ogni riga sono presenti campi distinti (pensa a loro come celle in un foglio di calcolo) separate da punto e virgola (;).
Awk elabora un record alla volta, quindi mentre stai strutturando le istruzioni che darai ad awk, puoi concentrarti solo su una riga. Stabilisci cosa vuoi fare con una riga, quindi provalo (mentalmente o con awk) sulla riga successiva e un po' di più. Ti ritroverai con una buona ipotesi su cosa deve fare il tuo script awk per fornirti la struttura dati che desideri.
In questo caso, è facile vedere che ogni campo è separato da un punto e virgola. Per semplicità, supponi di voler ordinare l'elenco in base al primo campo di ogni riga.
Prima di poter ordinare, devi essere in grado di concentrare awk solo sul primo campo di ogni riga, quindi questo è il primo passo. La sintassi di un comando awk in un terminale è awk , seguito dalle opzioni pertinenti, seguito dal comando awk e termina con il file di dati che desideri elaborare.
$ awk --field-separator=";" '{print $1;}' penguins.list
Aptenodytes
Pygoscelis
Eudyptula
Spheniscus
Megadyptes
Eudyptes
Torvaldis
Poiché il separatore di campo è un carattere che ha un significato speciale per la shell Bash, è necessario racchiudere il punto e virgola tra virgolette o precederlo con una barra rovesciata. Questo comando è utile solo per dimostrare che puoi concentrarti su un campo specifico. Puoi provare lo stesso comando utilizzando il numero di un altro campo per visualizzare il contenuto di un'altra "colonna" dei tuoi dati:
$ awk --field-separator=";" '{print $3;}' penguins.list
Miller,JF
Wagler
Bonaparte
Brisson
Milne-Edwards
Viellot
Ewing,L
Non è stato ancora risolto nulla, ma questo è un buon lavoro di base.
Scripting
Awk è più di un semplice comando; è un linguaggio di programmazione con indici, array e funzioni. Questo è significativo perché significa che puoi prendere un elenco di campi in base ai quali desideri ordinare, archiviare l'elenco in memoria, elaborarlo e quindi stampare i dati risultanti. Per una serie complessa di azioni come questa, è più facile lavorare in un file di testo, quindi crea un nuovo file chiamato sorter.awk e inserisci questo testo:
#!/usr/bin/awk -f
BEGIN {
FS=";";
}
Questo stabilisce il file come uno script awk che esegue le righe contenute nel file.
Il INIZIO istruzione è una funzione di configurazione speciale fornita da awk per attività che devono essere eseguite una sola volta. Definizione della variabile incorporata FS , che sta per separatore di campo ed è lo stesso valore che hai impostato nel comando awk con --field-separator , deve avvenire solo una volta, quindi è incluso in BEGIN dichiarazione.
Array in awk
Sai già come raccogliere i valori di un campo specifico utilizzando i $ notazione insieme al numero del campo, ma in questo caso è necessario memorizzarlo in un array anziché stamparlo sul terminale. Questo viene fatto con un array awk. La cosa importante di un array awk è che contenga chiavi e valori. Immagina una matrice su questo articolo; sarebbe simile a questo:autore:"seth",title:"Come ordinare con awk",length:1200 . Elementi come autore e titolo e lunghezza sono chiavi, con i seguenti contenuti come valori.
Il vantaggio di ciò nel contesto dell'ordinamento è che puoi assegnare qualsiasi campo come chiave e qualsiasi record come valore, quindi utilizzare la funzione awk incorporata asorti() (ordina per indice) per ordinare in base alla chiave. Per ora, supponi arbitrariamente di essere solo vuoi ordinare in base al secondo campo.
Awk affermazioni non preceduto dalle parole chiave speciali BEGIN o FINE sono loop che si verificano ad ogni record. Questa è la parte dello script che esegue la scansione dei dati per i modelli e li elabora di conseguenza. Ogni volta che awk rivolge la sua attenzione a un record, dichiarazioni in {} (a meno che non sia preceduto da BEGIN o FINE ) vengono eseguiti.
Per aggiungere una chiave e un valore a un array, crea una variabile (in questo script di esempio lo chiamo ARRAY , che non è originalissimo, ma molto chiaro) contenente un array, quindi assegnagli una chiave tra parentesi e un valore con il segno di uguale (= ).
{ # dump each field into an array
ARRAY[$2] = $R;
}
In questa dichiarazione, il contenuto del secondo campo ($2 ) sono usati come termine chiave e il record corrente ($R ) viene utilizzato come valore.
La funzione asorti()
Oltre agli array, awk ha diverse funzioni di base che puoi utilizzare come soluzioni semplici e veloci per attività comuni. Una delle funzioni introdotte in GNU awk, asorti() , offre la possibilità di ordinare un array per chiave (o indice ) o valore.
Puoi ordinare l'array solo dopo che è stato popolato, il che significa che questa azione non deve verificarsi con ogni nuovo record ma solo nella fase finale dello script. A tale scopo, awk fornisce lo speciale END parola chiave. L'inverso di BEGIN , un FINE l'istruzione avviene solo una volta e solo dopo che tutti i record sono stati scansionati.
Aggiungi questo al tuo script:
END {
asorti(ARRAY,SARRAY);
# get length
j = length(SARRAY);
for (i = 1; i <= j; i++) {
printf("%s %s\n", SARRAY[i],ARRAY[SARRAY[i]])
}
}
Gli asorti() la funzione prende il contenuto di ARRAY , lo ordina per indice e inserisce i risultati in un nuovo array chiamato SARRAY (un nome arbitrario che ho inventato per questo articolo, che significa Array Ordinato ).
Successivamente, la variabile j (un altro nome arbitrario) viene assegnato il risultato di length() funzione, che conta il numero di elementi in SARRAY .
Infine, usa un per ciclo per scorrere ogni elemento in SARRAY utilizzando printf() per stampare ogni chiave, seguita dal valore corrispondente di quella chiave in ARRAY .
Esecuzione dello script
Per eseguire il tuo script awk, rendilo eseguibile:
$ chmod +x sorter.awk
E poi eseguilo contro penguin.list dati di esempio:
$ ./sorter.awk penguins.list
antipodes Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
chrysocome Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
demersus Spheniscus;demersus;Brisson;1760;African
forsteri Aptenodytes;forsteri;Miller,JF;1778;Emperor
linux Torvaldis;linux;Ewing,L;1996;Tux
minor Eudyptula;minor;Bonaparte;1867;Little Blue
papua Pygoscelis;papua;Wagler;1832;Gentoo
Come puoi vedere, i dati sono ordinati in base al secondo campo.
Questo è un po' restrittivo. Sarebbe meglio avere la flessibilità di scegliere in fase di esecuzione quale campo si desidera utilizzare come chiave di ordinamento in modo da poter utilizzare questo script su qualsiasi set di dati e ottenere risultati significativi.
Aggiunta di opzioni di comando
Puoi aggiungere una variabile di comando a uno script awk utilizzando il valore letterale var nella tua sceneggiatura. Modifica lo script in modo che la tua clausola iterativa utilizzi var durante la creazione dell'array:
{ # dump each field into an array
ARRAY[$var] = $R;
}
Prova a eseguire lo script in modo che venga ordinato in base al terzo campo utilizzando -v var opzione quando lo esegui:
$ ./sorter.awk -v var=3 penguins.list
Bonaparte Eudyptula;minor;Bonaparte;1867;Little Blue
Brisson Spheniscus;demersus;Brisson;1760;African
Ewing,L Torvaldis;linux;Ewing,L;1996;Tux
Miller,JF Aptenodytes;forsteri;Miller,JF;1778;Emperor
Milne-Edwards Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
Viellot Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
Wagler Pygoscelis;papua;Wagler;1832;Gentoo
Correzioni
Questo articolo ha dimostrato come ordinare i dati in GNU awk puro. Lo script può essere migliorato, quindi, se ti è utile, dedica un po' di tempo alla ricerca delle funzioni di awk sulla pagina man di gawk e alla personalizzazione dello script per un output migliore.
Ecco lo script completo finora:
#!/usr/bin/awk -f
# GPLv3 appears here
# usage: ./sorter.awk -v var=NUM FILE
BEGIN { FS=";"; }
{ # dump each field into an array
ARRAY[$var] = $R;
}
END {
asorti(ARRAY,SARRAY);
# get length
j = length(SARRAY);
for (i = 1; i <= j; i++) {
printf("%s %s\n", SARRAY[i],ARRAY[SARRAY[i]])
}
}