Come analizzare un file CSV in Bash?


112

Sto lavorando a una lunga sceneggiatura di Bash. Voglio leggere le celle da un file CSV nelle variabili Bash. Posso analizzare le righe e la prima colonna, ma non qualsiasi altra colonna. Ecco il mio codice finora:


  cat myfile.csv|while read line
  do
    read -d, col1 col2 < <(echo $line)
    echo "I got:$col1|$col2"
  done

Stampa solo la prima colonna. Come test aggiuntivo, ho provato quanto segue:

read -d, x y < <(echo a,b,)

E $ y è vuoto. Quindi ho provato:

read x y < <(echo a b)

E $ y lo è b. Perché?


7
avete considerato awkda usare $1, $2ecc?
BeemerGuy

4
come nota a margine: comando <<(echo "stringa") ---> comando <<< "stringa"
tokland

1
Il programma della riga di comando "cut" è stato progettato per questo: ss64.com/bash/cut.html
Jay

Risposte:


215

Devi usare IFSinvece di -d:

while IFS=, read -r col1 col2
do
    echo "I got:$col1|$col2"
done < myfile.csv

Nota che per l'analisi CSV di uso generale dovresti usare uno strumento specializzato in grado di gestire i campi tra virgolette con virgole interne, tra gli altri problemi che Bash non può gestire da solo. Esempi di tali strumenti sono cvstoole csvkit.


7
La soluzione proposta va bene per file CSV molto semplici, cioè se le intestazioni ei valori sono privi di virgole e virgolette incorporate. In realtà è abbastanza complicato scrivere un parser CSV generico (soprattutto perché ci sono diversi "standard" CSV). Un approccio per rendere i file CSV più adatti agli strumenti * nix consiste nel convertirli in TSV (valori separati da tabulazioni), ad esempio utilizzando Excel.
picco

È interessante che non posso fare mkdir nel corpo. Sto ottenendo command not found. Solo le echoopere.
Zsolt

1
@ Zsolt: non c'è motivo per cui dovrebbe essere così. Devi avere un errore di battitura o un carattere randagio non stampabile.
In pausa fino a nuovo avviso.

2
@DennisWilliamson Dovresti allegare il separatore, ad esempio quando usi ;:while IFS=";" read col1 col2; do ...
thomas.mc.work

1
@ thomas.mc.work: Questo è vero nel caso di punti e virgola e altri caratteri speciali per la shell. Nel caso di una virgola, non è necessario e tendo a preferire omettere i caratteri che non sono necessari. Ad esempio, puoi sempre specificare le variabili per l'espansione usando le parentesi graffe (ad esempio ${var}), ma le ometto quando non sono necessarie. A me sembra più pulito.
In pausa fino a nuovo avviso.

10

Dalla manpagina:

-d delim Il primo carattere di delim viene utilizzato per terminare la riga di input, piuttosto che la nuova riga.

Stai usando -d,che terminerà la riga di input sulla virgola. Non leggerà il resto della riga. Ecco perché $ y è vuoto.


3

Possiamo analizzare i file CSV con stringhe tra virgolette e delimitati da say | con il seguente codice

while read -r line
do
    field1=$(echo $line | awk -F'|' '{printf "%s", $1}' | tr -d '"')
    field2=$(echo $line | awk -F'|' '{printf "%s", $2}' | tr -d '"')

    echo $field1 $field2
done < $csvFile

awk analizza i campi stringa in variabili e tr rimuove le virgolette.

Leggermente più lento poiché awk viene eseguito per ogni campo.


1
Bene, puoi anche usare coma (,)
pkarc

0

Se vuoi leggere il file CSV con alcune righe, questa è la soluzione.

while IFS=, read -ra line
do 
    test $i -eq 1 && ((i=i+1)) && continue
    for col_val in ${line[@]}
    do
        echo -n "$col_val|"                 
    done
    echo        
done < "$csvFile"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.