Come analizzare i dati CSV in Bash

Pubblicato: 2022-09-16
Jane Kelly/Shutterstock.com

I file CSV (Comma Separated Values) sono uno dei formati più comuni per i dati esportati. Su Linux, possiamo leggere i file CSV usando i comandi Bash. Ma può diventare molto complicato, molto rapidamente. Daremo una mano.

Che cos'è un file CSV?

Un file di valori separati da virgola è un file di testo che contiene dati tabulati. CSV è un tipo di dati delimitati. Come suggerisce il nome, una virgola " , " viene utilizzata per separare ogni campo di dati, o valore, dai suoi vicini.

Che cos'è un file CSV e come lo apro?
CORRELATI Che cos'è un file CSV e come lo apro?

CSV è ovunque. Se un'applicazione dispone di funzioni di importazione ed esportazione, supporterà quasi sempre CSV. I file CSV sono leggibili dall'uomo. Puoi guardarci dentro con meno, aprirli in qualsiasi editor di testo e spostarli da un programma all'altro. Ad esempio, puoi esportare i dati da un database SQLite e aprirlo in LibreOffice Calc.

Tuttavia, anche CSV può diventare complicato. Vuoi avere una virgola in un campo dati? Questo campo deve essere racchiuso tra virgolette " " ". Per includere le virgolette in un campo, ciascuna virgoletta deve essere inserita due volte.

Ovviamente, se stai lavorando con CSV generato da un programma o uno script che hai scritto, è probabile che il formato CSV sia semplice e diretto. Se sei costretto a lavorare con formati CSV più complessi, essendo Linux Linux, ci sono soluzioni che possiamo usare anche per questo.

Alcuni dati di esempio

Puoi facilmente generare alcuni dati CSV di esempio, utilizzando siti come Online Data Generator. Puoi definire i campi che desideri e scegliere quante righe di dati desideri. I tuoi dati vengono generati utilizzando valori fittizi realistici e scaricati sul tuo computer.

Abbiamo creato un file contenente 50 righe di informazioni fittizie sui dipendenti:

  • id : un valore intero univoco semplice.
  • nome : il nome della persona.
  • cognome : il cognome della persona.
  • job-title : il titolo di lavoro della persona.
  • indirizzo e-mail : l'indirizzo e-mail della persona.
  • branch : il ramo aziendale in cui lavorano.
  • state : lo stato in cui si trova la filiale.

Alcuni file CSV hanno una riga di intestazione che elenca i nomi dei campi. Il nostro file di esempio ne ha uno. Ecco la parte superiore del nostro file:

Il file CSV di esempio

La prima riga contiene i nomi dei campi come valori separati da virgole.

Analisi dei dati Forma il file CSV

Scriviamo uno script che leggerà il file CSV ed estrarrà i campi da ogni record. Copia questo script in un editor e salvalo in un file chiamato "field.sh".

 #! /bin/bash

while IFS="," read -r id nome cognome jobtitle email branch state
fare
  echo "ID record: $id"
  echo "Nome: $nome"
  echo " Cognome: $cognome"
  echo "Titolo lavoro: $titolo lavoro"
  echo "Aggiungi email: $email"
  echo " Ramo: $ramo"
  echo "Stato: $stato"
  eco ""
done <(tail -n +2 sample.csv)

C'è un bel po' di cose nel nostro piccolo copione. Analizziamolo.

Come elaborare un file riga per riga in uno script Bash Linux
CORRELATI Come elaborare un file riga per riga in uno script Bash Linux

Stiamo usando un ciclo while . Finché la condizione del ciclo while si risolve in true, il corpo del ciclo while verrà eseguito. Il corpo del ciclo è abbastanza semplice. Una raccolta di istruzioni echo viene utilizzata per stampare i valori di alcune variabili nella finestra del terminale.

La condizione del ciclo while è più interessante del corpo del ciclo. Specifichiamo che una virgola deve essere utilizzata come separatore di campo interno, con l'istruzione IFS="," . L'IFS è una variabile d'ambiente. Il comando read fa riferimento al suo valore durante l'analisi di sequenze di testo.

Stiamo usando l'opzione -r (conserva barre inverse) del comando di read per ignorare eventuali barre inverse che potrebbero essere presenti nei dati. Saranno trattati come caratteri normali.

Il testo analizzato dal comando di read viene archiviato in una serie di variabili denominate in base ai campi CSV. Avrebbero potuto essere nominati altrettanto facilmente field1, field2, ... field7 , ma i nomi significativi semplificano la vita.

I dati sono ottenuti come output dal comando tail . Stiamo usando tail perché ci offre un modo semplice per saltare la riga di intestazione del file CSV. L'opzione -n +2 (numero riga) dice a tail di iniziare a leggere dalla riga numero due.

Il costrutto <(...) è chiamato sostituzione di processo. Fa sì che Bash accetti l'output di un processo come se provenisse da un descrittore di file. Questo viene quindi reindirizzato nel ciclo while , fornendo il testo che il comando di read analizzerà.

Rendi eseguibile lo script usando il comando chmod . Dovrai farlo ogni volta che copi uno script da questo articolo. Sostituire in ogni caso il nome dello script appropriato.

 chmod +x campo.sh 

Rendere eseguibile uno script con chmod

Quando eseguiamo lo script, i record vengono suddivisi correttamente nei loro campi costitutivi, con ogni campo memorizzato in una variabile diversa.

 ./campo.sh 

Il file CSV analizzato dallo script field.sh.

Ogni record viene stampato come un insieme di campi.

Selezione dei campi

Forse non vogliamo o non dobbiamo recuperare ogni campo. Possiamo ottenere una selezione di campi incorporando il comando di cut .

Questo script è chiamato "select.sh".

 #!/bin/bash

while IFS="," read -r id stato del ramo del titolo di lavoro
fare
  echo "ID record: $id"
  echo "Titolo lavoro: $titolo lavoro"
  echo " Ramo: $ramo"
  echo "Stato: $stato"
  eco ""
done <(cut -d "," -f1,4,6,7 sample.csv | tail -n +2)

Abbiamo aggiunto il comando cut nella clausola di sostituzione del processo. Stiamo usando l'opzione -d (delimitatore) per dire a cut di usare le virgole “ , ” come delimitatore. L'opzione -f (campo) dice a cut che vogliamo i campi uno, quattro, sei e sette. Questi quattro campi vengono letti in quattro variabili, che vengono stampate nel corpo del ciclo while .

Questo è ciò che otteniamo quando eseguiamo lo script.

 ./seleziona.sh 

Analisi del file CSV con field.sh per estrarre una specifica selezione di campi

Aggiungendo il comando cut , possiamo selezionare i campi che vogliamo e ignorare quelli che non vogliamo.

Fin qui tutto bene. Ma…

Se il CSV con cui hai a che fare non è complicato senza virgole o virgolette nei dati dei campi, ciò che abbiamo trattato probabilmente soddisferà le tue esigenze di analisi CSV. Per mostrare i problemi che possiamo incontrare, abbiamo modificato un piccolo campione di dati in modo che assomigli a questo.

 id,nome,cognome,titolo del lavoro,indirizzo e-mail,filiale,stato
1,Rosalyn,Brennan,"Steward, Senior",[email protected],Minneapolis,Maryland
2,Danny,Redden,"Analista ""Budget""",[email protected],Venezia,Carolina del Nord
3,Lexi,Roscoe,Farmacista,,Irlington,Vermont
  • Il record uno ha una virgola nel campo job-title , quindi il campo deve essere racchiuso tra virgolette.
  • Il record due ha una parola racchiusa tra due serie di virgolette nel campo jobs-title .
  • Il record tre non ha dati nel campo email-address .

Questi dati sono stati salvati come "sample2.csv". Modifica il tuo script "field.sh" per chiamare "sample2.csv" e salvalo come "field2.sh".

 #! /bin/bash

while IFS="," read -r id nome cognome jobtitle email branch state
fare
  echo "ID record: $id"
  echo "Nome: $nome"
  echo " Cognome: $cognome"
  echo "Titolo lavoro: $titolo lavoro"
  echo "Aggiungi email: $email"
  echo " Ramo: $ramo"
  echo "Stato: $stato"
  eco ""
fatto < <(tail -n +2 sample2.csv)

Quando eseguiamo questo script, possiamo vedere delle crepe che appaiono nei nostri semplici parser CSV.

 ./field2.sh 

Esecuzione di field2.sh

Il primo record divide il campo del titolo di lavoro in due campi, trattando la seconda parte come l'indirizzo e-mail. Ogni campo dopo questo viene spostato di un posto a destra. L'ultimo campo contiene sia il branch che i valori di state .

Un record con un campo diviso in due campi

Il secondo record conserva tutte le virgolette. Dovrebbe contenere solo una coppia di virgolette attorno alla parola "Budget".

Un record con virgolette mal gestite

Il terzo record gestisce effettivamente il campo mancante come dovrebbe. Manca l'indirizzo email, ma tutto il resto è come dovrebbe essere.

Un record con un campo mancante, che viene gestito correttamente

Controintuitivamente, per un semplice formato di dati, è molto difficile scrivere un robusto parser CSV generico. Strumenti come awk ti permetteranno di avvicinarti, ma ci sono sempre casi limite ed eccezioni che sfuggono.

Come utilizzare il comando awk su Linux
CORRELATI Come utilizzare il comando awk su Linux

Cercare di scrivere un parser CSV infallibile probabilmente non è il modo migliore per procedere. Un approccio alternativo, soprattutto se stai lavorando per una scadenza di qualche tipo, utilizza due strategie diverse.

Uno consiste nell'utilizzare uno strumento appositamente progettato per manipolare ed estrarre i dati. Il secondo è disinfettare i tuoi dati e sostituire scenari problematici come virgole e virgolette incorporate. I tuoi semplici parser Bash possono quindi far fronte al CSV compatibile con Bash.

Il csvkit Toolkit

Il CSV toolkit csvkit è una raccolta di utilità appositamente creata per aiutare a lavorare con i file CSV. Dovrai installarlo sul tuo computer.

Per installarlo su Ubuntu, usa questo comando:

 sudo apt install csvkit 

Installazione di csvkit su Ubuntu

Per installarlo su Fedora, devi digitare:

 sudo dnf install python3-csvkit 

Installazione di csvkit su Fedora

Su Manjaro il comando è:

 sudo pacman -S csvkit 

Installazione di csvkit su Manjaro

Se gli passiamo il nome di un file CSV, l'utilità csvlook mostra una tabella che mostra il contenuto di ogni campo. Il contenuto del campo viene visualizzato per mostrare cosa rappresentano i contenuti del campo, non come sono archiviati nel file CSV.

Proviamo csvlook con il nostro file problematico "sample2.csv".

 csvlook sample2.csv 

CSV problematico analizzato correttamente da csvlook

Tutti i campi sono visualizzati correttamente. Questo dimostra che il problema non è il CSV. Il problema è che i nostri script sono troppo semplicistici per interpretare correttamente il CSV.

Per selezionare colonne specifiche, utilizzare il comando csvcut . L'opzione -c (colonna) può essere utilizzata con nomi di campo o numeri di colonna o una combinazione di entrambi.

Supponiamo di dover estrarre il nome e il cognome, i titoli di lavoro e gli indirizzi e-mail da ciascun record, ma vogliamo che l'ordine dei nomi sia "cognome, nome". Tutto quello che dobbiamo fare è mettere i nomi dei campi oi numeri nell'ordine in cui li vogliamo.

Questi tre comandi sono tutti equivalenti.

 csvcut -c cognome, nome, titolo del lavoro, indirizzo e-mail sample2.csv
 csvcut -c cognome, nome,4,5 sample2.csv
 csvcut -c 3,2,4,5 sample2.csv 

Prelievo dei campi in un ordine preferito con csvcut

Possiamo aggiungere il comando csvsort per ordinare l'output in base a un campo. Utilizziamo l'opzione -c (colonna) per specificare la colonna in base alla quale eseguire l'ordinamento e l'opzione -r (inversa) per ordinare in ordine decrescente.

 csvcut -c 3,2,4,5 sample2.csv | csvsort -c 1 -r 

Selezionare i campi e ordinarli in base a una singola colonna

Per rendere l'output più bello possiamo alimentarlo tramite csvlook .

 csvcut -c 3,2,4,5 sample2.csv | csvsort -c 1 -r | csvlook 

Utilizzo di csvlook per stampare in modo grazioso la selezione ordinata dei campi

Un bel tocco è che, anche se i record sono ordinati, la riga di intestazione con i nomi dei campi viene mantenuta come prima riga. Una volta che siamo felici di avere i dati nel modo desiderato, possiamo rimuovere csvlook dalla catena di comando e creare un nuovo file CSV reindirizzando l'output in un file.

Abbiamo aggiunto più dati a "sample2.file", rimosso il comando csvsort e creato un nuovo file chiamato "sample3.csv".

 csvcut -c 3,2,4,5 sample2.csv > sample3.csv 

Un modo sicuro per disinfettare i dati CSV

Se apri un file CSV in LibreOffice Calc, ogni campo verrà inserito in una cella. Puoi utilizzare la funzione trova e sostituisci per cercare le virgole. Potresti sostituirli con "niente" in modo che svaniscano, o con un carattere che non influisca sull'analisi CSV, come un punto e virgola " ; " Per esempio.

Non vedrai le virgolette intorno ai campi tra virgolette. Le uniche virgolette che vedrai sono le virgolette incorporate all'interno dei dati del campo. Questi sono visualizzati come virgolette singole. Trovarli e sostituirli con un unico apostrofo “ ' ” sostituiranno le virgolette doppie nel file CSV.

Utilizzo di trova e sostituisci di LibreOffice Calc per sostituire le virgolette con gli apostrofi

Trovare e sostituire in un'applicazione come LibreOffice Calc significa che non è possibile eliminare accidentalmente nessuna delle virgole del separatore di campo, né eliminare le virgolette attorno ai campi tra virgolette. Cambierai solo i valori dei dati dei campi.

Abbiamo modificato tutte le virgole nei campi con punto e virgola e tutte le virgolette incorporate con apostrofi e abbiamo salvato le modifiche.

Il file CSV modificato

Abbiamo quindi creato uno script chiamato "field3.sh" per analizzare "sample3.csv".

 #! /bin/bash

while IFS="," read -r cognome nome nome lavoro e-mail
fare
  echo " Cognome: $cognome"
  echo "Nome: $nome"
  echo "Titolo lavoro: $titolo lavoro"
  echo "Aggiungi email: $email"
  eco ""
done <(tail -n +2 sample3.csv)

Vediamo cosa otteniamo quando lo eseguiamo.

 ./field3.sh 

Una sezione di CSV analizzato correttamente

Il nostro semplice parser ora può gestire i nostri record precedentemente problematici.

Vedrai un sacco di CSV

CSV è probabilmente la cosa più vicina a una lingua comune per i dati delle applicazioni. La maggior parte delle applicazioni che gestiscono una qualche forma di dati supporta l'importazione e l'esportazione di CSV. Sapere come gestire CSV, in modo realistico e pratico, ti sarà di grande aiuto.

CORRELATI: 9 esempi di script Bash per iniziare su Linux