Wie analysiere ich eine CSV-Datei in Bash?

111

Ich arbeite an einem langen Bash-Skript. Ich möchte Zellen aus einer CSV-Datei in Bash-Variablen lesen. Ich kann Zeilen und die erste Spalte analysieren, aber keine andere Spalte. Hier ist mein Code bisher:


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

Es wird nur die erste Spalte gedruckt. Als zusätzlichen Test habe ich Folgendes versucht:

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

Und $ y ist leer. Also habe ich versucht:

read x y < <(echo a b)

Und $ y ist b. Warum?

Benutzer1
quelle
7
haben Sie darüber nachgedacht , awkzu verwenden $1, $2usw.?
BeemerGuy
4
als Nebenbemerkung: Befehl << (echo "string") ---> Befehl <<< "string"
tokland
1
Das Befehlszeilenprogramm 'cut' wurde dafür entwickelt: ss64.com/bash/cut.html
Jay

Antworten:

214

Sie müssen IFSanstelle von verwenden -d:

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

Beachten Sie, dass Sie für das allgemeine CSV-Parsen ein spezielles Tool verwenden sollten, das Anführungszeichen mit internen Kommas verarbeiten kann, unter anderem Probleme, die Bash nicht selbst behandeln kann. Beispiele für solche Werkzeuge sind cvstoolund csvkit.

Bis auf weiteres angehalten.
quelle
7
Die vorgeschlagene Lösung eignet sich für sehr einfache CSV-Dateien, dh wenn die Überschriften und Werte frei von Kommas und eingebetteten Anführungszeichen sind. Es ist eigentlich ziemlich schwierig, einen generischen CSV-Parser zu schreiben (zumal es mehrere CSV- "Standards" gibt). Ein Ansatz, um CSV-Dateien für * nix-Tools zugänglicher zu machen, besteht darin, sie in TSV (durch Tabulatoren getrennte Werte) zu konvertieren, z. B. mithilfe von Excel.
Peak
Es ist interessant, dass ich im Körper kein Mkdir machen kann. Ich bekomme command not found. Nur die echoWerke.
Zsolt
1
@ Zsolt: Es gibt keinen Grund, warum dies der Fall sein sollte. Sie müssen einen Tippfehler oder ein streunendes, nicht druckbares Zeichen haben.
Bis auf weiteres angehalten.
2
@ TennisWilliamson Sie sollten den Separator einschließen, zB wenn Sie verwenden ;:while IFS=";" read col1 col2; do ...
thomas.mc.work
1
@ thomas.mc.work: Dies gilt für Semikolons und andere Zeichen, die für die Shell besonders sind. Im Falle eines Kommas ist dies nicht erforderlich, und ich ziehe es vor, unnötige Zeichen wegzulassen. Zum Beispiel könnten Sie Variablen für die Erweiterung immer mit geschweiften Klammern angeben (z. B. ${var}), aber ich lasse sie weg, wenn sie nicht erforderlich sind. Für mich sieht es sauberer aus.
Bis auf weiteres angehalten.
10

Von der manSeite:

-d delim Das erste Zeichen von delim wird verwendet, um die Eingabezeile und nicht die neue Zeile zu beenden.

Sie verwenden, -d,wodurch die Eingabezeile auf dem Komma beendet wird. Der Rest der Zeile wird nicht gelesen. Deshalb ist $ y leer.

Dogbane
quelle
3

Wir können CSV-Dateien mit in Anführungszeichen gesetzten Zeichenfolgen analysieren, die durch say | begrenzt sind mit folgendem Code

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 analysiert die Zeichenfolgenfelder in Variablen und tr entfernt das Anführungszeichen.

Etwas langsamer als awk für jedes Feld ausgeführt wird.

Maithilish
quelle
1
Gut, Sie können auch coma (,)
pkarc
0

Wenn Sie eine CSV-Datei mit einigen Zeilen lesen möchten, ist dies die Lösung.

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"
Eliya
quelle