BASH: estrarre le colonne e le righe desiderate da un file CSV con i comandi cut, tail e tr

In questo articolo vediamo come effettuare delle veloci operazioni di estrazione dati da file di testo che presentano dati strutturati, organizzati in righe e con gli elementi di ciascuna riga separati da un determinato carattere. I classici file CSV o similari, per intenderci.

Capita spesso di dover estrarre da file di questo tipo un determinato subset di colonne di interesse, tralasciando le altre. Un’operazione di questo tipo può essere eseguita facilmente sui sistemi unix-like utilizzando dei comandi di shell.

Vediamo un esempio pratico; supponiamo di avere un file di testo contenente le informazioni sugli utenti, organizzato come segue:

ID;Nome;Cognome;Età;Sesso;Città;Tel;Email;
0001;Davis;Molinari;32;M;Trino;000-123456789;davismolinari@email.com
0002;Mario;Bianchi;50;M;Milano;02-987654;mariobianchi@email.com
0003;Paolo;Rossi;45;M;Torino;011-555443;paolorossi@email.com
0004;Maria;Neri;35;F;Roma;00-2121212;marianeri@email.com

Il nostro file presenta una prima riga di intestazione e successivamente le righe che contengono le informazioni anagrafiche e di contatto degli utenti. In ciascuna riga i vari elementi sono divisi tra loro da un carattere separatore che in questo caso è rappresentato dal ‘;’ (punto e virgola).

Supponiamo ora di voler estrarre dal file originale solo alcune colonne, ad esempio le colonne “Nome”, “Cognome” ed “Email” e salvare il nuovo subset di dati su un nuovo file.

Il contenuto del nuovo file dovrà quindi essere il seguente:

Nome;Cognome;Email
Davis;Molinari;davismolinari@email.com
Mario;Bianchi;mariobianchi@email.com
Paolo;Rossi;paolorossi@email.com
Maria;Neri;marianeri@email.com

Questo risultato possiamo facilmente ottenerlo grazie al comando cut.
Questo comando ci permette di specificare, tramite l’opzione -d, il delimitatore che separa i campi delle nostre righe e tramite l’opzione -f gli indici delle colonne che vogliamo estrarre.
Gli indici delle colonne partono da 1, per cui per ottenere il nostro obbiettivo dobbiamo estrarre le colonne 2 (Nome), 3 (Cognome) e 8 (Email).

Eseguiamo il comando: cut -d ‘;’ -f 2,3,8 ListaUtenti.txt > ListaOutput1.txt
cut -d -f command
Come si vede dall’immagine precedente il file creato con il comando contiene esattamente l’estratto dei dati che volevamo.
Le colonne da estrarre indicate all’opzione -f possono essere elencate singolarmente, separandole da una ‘,’ (virgola) nell’elenco oppure come intervalli separando in questo caso gli estremi dell’intervallo con un ‘-‘. (Esempio: cut -d ‘;’ -f 1-4)

Ora proviamo ad aggiungere qualche altra operazione.
Spesso alcuni valori delle righe di un file .csv sono racchiusi tra apici o doppi apici. Supponiamo ad esempio di avere nuovamente il contenuto del nostro file originale, in cui però questa volta racchiudiamo tra virgolette il valore degli indirizzi email. Modifichiamo quindi li file “ListaUtenti.txt” affinchè contenga:

ID;Nome;Cognome;Età;Sesso;Città;Tel;Email;
0001;Davis;Molinari;32;M;Trino;000-123456789;"davismolinari@email.com"
0002;Mario;Bianchi;50;M;Milano;02-987654;"mariobianchi@email.com"
0003;Paolo;Rossi;45;M;Torino;011-555443;"paolorossi@email.com"
0004;Maria;Neri;35;F;Roma;00-2121212;"marianeri@email.com"

Quello che vogliamo fare è ottenere lo stesso output di prima, per cui questa volta oltre a selezionare le colonne che ci interessano dobbiamo rimuovere le virgolette dai valori della colonna Email.
Per farlo utilizziamo il comando tr (translate characters) con l’opzione -d, con la quale gli indichiamo di cancellare i caratteri che gli forniamo, al quale inoltriamo tramite ‘|’ (pipe) l’output del nostro comando cut.

Eseguiamo il comando: cut -d ‘;’ -f 2,3,8 ListaUtenti.txt | tr -d ‘”‘ > ListaOutput2.txt
cut and tr command
Dall’immagine possiamo vedere che il contenuto è nuovamente uguale al precedente e abbiamo eliminato le virgolette che racchiudevano i valori della colonna email.

Aggiungiamo infine un ulteriore raffinamento.
In genere questa tipologia di file presenta una prima riga di intestazione in cui sono elencati i nomi delle colonne a cui corrispondono i valori delle righe seguenti. Spesso questa riga intestazione si ha la necessità di eliminarla.
Quindi ora, partendo sempre dal file degli utenti, contenente ancora le virgolette intorno ai valori email, vogliamo ottenere l’output seguente, in cui la riga di intestazione è stata eliminata:

Davis;Molinari;davismolinari@email.com
Mario;Bianchi;mariobianchi@email.com
Paolo;Rossi;paolorossi@email.com
Maria;Neri;marianeri@email.com

Per fare questo ci viene incontro il comando tail. Tale comando, di base, ci permette di mostrare le ultime 10 righe di un file. Esso presenta però l’interessante opzione -n che permette di specificare:

  • Il numero di righe da estrarre a partire dal fondo, specificando un intero
  • Il numero di riga da cui partire specificandolo preceduto da un +

Esempi:
tail -n 4 estrae le ultime 4 righe
tail -n +2 estrae le righe dalla seconda in poi

Ed è proprio quest’ultima opzione che fa al caso nostro!

Eseguiamo il comando: cut -d ‘;’ -f 2,3,8 ListaUtenti.txt | tail -n +2 | tr -d ‘”‘ > ListaOutput3.txt
cut tail and tr commands
Come possiamo vedere dall’immagine abbiamo ottenuto il risultato desiderato in quanto abbiamo eliminato sia la riga di intestazione che le virgolette.

Leave a Reply

Your email address will not be published. Required fields are marked *