GUIDA AD AWK, 03 – lettura/split

Lettura file e split del contenuto

# File di partenza:
 $ cat pluto
 casa mattoni grande
 albero legno medio
 strada asfalto lunga
 borsa pelle piccola
# Stampa il terzo campo di tutte le righe del file pluto che contengono la parola "borsa"
 $ awk '/borsa/ {print $3}' pluto
 piccola
# Stampa il primo campo di tutte le righe del file pluto che contengono la parola "medio"
 awk '/medio/ {print $1}' pluto
 albero
# Stampa tutti i campi di tutte le righe del file pluto che contengono la parola "medio"
 $ awk '/medio/ {print $0}' pluto
 albero legno medio

Vediamo ora qualche esempio un po’ più articolato:

# File di partenza:
 $ cat file1
 Name Domain
 Deepak Banking
 Neha Telecom
 Vijay Finance
 Guru Migration

Abbiamo quindi un file con dati strutturati in forma di tabella, nella quale la prima riga è l’intestazione(record header). Per stampare tutto il file senza l’intestazione, dovremo includere nella stampa tutti i record diversi dal record 1, utilizzando, ad esempio, il pattern (NR!=1). Ricordiamo che la variabile NR è quella che contiene il numero di riga:

$ awk '(NR!=1){print $0}' file1
 Deepak Banking
 Neha Telecom
 Vijay Finance
 Guru Migration

Se il numero di riga è diverso da 1, stampa tutti i campi

Vediamo ora la variabile FS (separatore di campo) in azione:

# File di partenza:
 $ cat file2
 Name,Domain,Expertise
 Deepak,Banking,MQ
 Neha,Telecom,Power
 Vijay,Finance,CRM
 Guru,Migration,Unix

Abbiamo una lista di valori separati da virgola. Se chiediamo a awk di stampare la prima colonna in realtà stamperà tutto il contenuto perchè il separatore di campo (FS) di default è lo spazio e non la virgola:

$ awk '{print $1}' file2
 Name,Domain,Expertise
 Deepak,Banking,MQ
 Neha,Telecom,Power
 Vijay,Finance,CRM
 Guru,Migration,Unix

Per stampare solo la prima colonna dovrò in questo caso specificare che nel file di input il separatore è la virgola:

$ awk 'BEGIN{(FS=",")} {print $1}' file2
 Name
 Deepak
 Neha
 Vijay
 Guru

o più semplicemente indichiamo il separatore di campo attraverso l’opzione -F di awk:

$ awk -F"," '{print $1}' file2
 Name
 Deepak
 Neha
 Vijay
 Guru

E ancora:

$ awk -F, '{print $2}' file2
 Domain
 Banking
 Telecom
 Finance
 Migration

FS si può anche settare in altro modo:

$ awk '{print $1}' FS="," file2
 Name Expertise
 Deepak MQ
 Neha Power
 Vijay CRM
 Guru Unix

Ora mettiamo un po’ di elementi assieme e aggiungiamo anche la variabile OFS, che setta il separatore di campo in output:

$ awk -F"," 'NR!=1{print $1,$3}' OFS=" - " file2
 Deepak - MQ
 Neha - Power
 Vijay - CRM
 Guru - Unix

Utilizziamo ciò che abbiamo già visto per eseguire operazioni un po’ più avanzate.
Prendiamo il file strutturato:

$ cat file4
 primo,100
 secondo,200
 terzo,300
 quarto,400
 quinto,500
 sesto,600
 settimo,700
 ottavo,800
$ awk -F, '{print > $1".txt"}' file4

Il comando stamperà ogni riga e la redigerà in un file che si chiamerà con il valore del primo campo+ estensione .txt. Avremo così creato un file primo.txt che conterrà “primo,100″, un file secondo.txt che conterrà “secondo,200″ e così via.

Ora un’ulteriore evoluzione con “if … else”:

$ awk -F, '{if($2<=400)print > "finoa400.txt";else print > "da401.txt"}' file4

Il comando stampa in “finoa400.txt” le righe in cui il valore del secondo campo è uguale o superiore a 400, altrimenti tutte le altre le scrive in da401.txt:

$ cat finoa400.txt
 primo,100
 secondo,200
 terzo,300
 quarto,400
 $ cat da400.txt da401.txt
 quinto,500
 sesto,600
 settimo,700
 ottavo,800

Un modo per ottenere gli stessi risultati è utilizzare l’operatore ternario in awk:

$ awk -F, '{x=($2<=4)?"finoa400.txt":"da401.txt"; print > x}' file1

——————————————
Inciso sull’operatore ternario di C:
exp1 ? exp2 : exp3
Corrisponde al blocco if-else:
if (exp1)
{
exp2;
} else {
exp3;
}

Significa: se exp1 è vera esegui exp2, altrimenti esegui exp3
——————————————–

Altro caso:

# File di partenza:
 $ cat test5
 INIZIO
 pippo
 pluto
 paperino
 INIZIO
 paperoga
 paperinik
 minnie
 cip
 INIZIO
 ciop
 qui
 quo
 INIZIO
 qua
 paperina
 paperone
 basettoni
 nonnapapera
 duck

Vogliamo che venga creato un nuovo file ogni volta che viene trovata la ricorrenza “INIZIO”:

$ awk '/INIZIO/{x="fileoutput"++i;}{print > x;}' test5
$ ls fileoutput*
 fileoutput1 fileoutput2 fileoutput3 fileoutput4

Entrando nei singoli file prodotti si vedrà il contenuto del primo file splittato sui file creati rispettando la successione:

$ cat fileoutput1
 INIZIO
 pippo
 pluto
 paperino
 $ cat fileoutput2
 INIZIO
 paperoga
 paperinik
 minnie
 cip
 $ cat fileoutput3
 INIZIO
 ciop
 qui
 quo
 $ cat fileoutput4
 INIZIO
 qua
 paperina
 paperone
 basettoni
 nonnapapera
 duck

Elaborando poi lo stesso comando, possiamo eliminare l’header “INIZIO”:

$ awk '/INIZIO/{x="fileoutput"++i;next}{print > x;}' test5

“next” -> indica ad awk di stoppare immediatamente il processamento della riga e di passare alla riga seguente. Di conseguenza la riga non viene stampata.

oppure variare l’header:

$ awk '/INIZIO/{x="fileoutput"++i;print "INTESTAZIONE";next}{print > x;}' test5

Ora vogliamo che il file sia splittato in più file ogni 3 righe:

$ awk 'NR%3==1{x="F"++i;}{print > x}' test5
 $ ls F*
 F1 F2 F3 F4 F5 F6 F7

“NR%3==1″ -> l’operatore “%” indica il RESTO della divisione NR/3. Solo se il resto è uguale a 1 la riga viene stampata nel file F1, F2, F3…

————————————

INDICE

Lascia una risposta

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *

È possibile utilizzare questi tag ed attributi XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>