Wie parse ich eine CSV-Datei in Bash?
Kommen Sie zu spät zu dieser Frage und da Bash neue Funktionen bietet, da sich diese Frage auf Bash bezieht und keine der bereits geposteten Antworten diese leistungsstarke und konforme Methode zeigt, genau dies zu tun .
Parsen von CSV-Dateien unter bash
, mit ladbarem Modul
Entspricht RFC 4180 , eine Zeichenfolge wie diese Beispiel-CSV-Zeile :
12,22.45,"Hello, ""man"".","A, b.",42
sollte aufgeteilt werden als
1 12
2 22.45
3 Hello, "man".
4 A, b.
5 42
bash ladbar .C kompilierte Module.
Unter Bash können Sie ladbare c-kompilierte Module erstellen, bearbeiten und verwenden . Einmal geladen, funktionieren sie wie alle anderen integrierten !! (Weitere Informationen finden Sie unter Quellbaum.;)
Der aktuelle Quellbaum (15. Oktober 2021, bash V5.1-rc3) enthält eine Reihe von Beispielen:
accept listen for and accept a remote network connection on a given port
asort Sort arrays in-place
basename Return non-directory portion of pathname.
cat cat(1) replacement with no options - the way cat was intended.
csv process one line of csv data and populate an indexed array.
dirname Return directory portion of pathname.
fdflags Change the flag associated with one of bash's open file descriptors.
finfo Print file info.
head Copy first part of files.
hello Obligatory "Hello World" / sample loadable.
...
tee Duplicate standard input.
template Example template for loadable builtin.
truefalse True and false builtins.
tty Return terminal name.
uname Print system information.
unlink Remove a directory entry.
whoami Print out username of current user.
Es gibt ein voll funktionsfähiges cvs
Parser einsatzbereit in examples/loadables
Verzeichnis:csv.c !!
Unter Debian GNU/Linux-basierten Systemen müssen Sie möglicherweise das bash-builtins-Paket von
installierenapt install bash-builtins
Mit ladbaren Bash-Builtins :
Dann:
enable -f /usr/lib/bash/csv csv
Von dort aus könnten Sie csv
verwenden als bash builtin .
Mit meinem Beispiel:12,22.45,"Hello, ""man"".","A, b.",42
csv -a myArray '12,22.45,"Hello, ""man"".","A, b.",42'
printf "%s\n" "${myArray[@]}" | cat -n
1 12
2 22.45
3 Hello, "man".
4 A, b.
5 42
Dann in einer Schleife eine Datei verarbeiten.
while IFS= read -r line;do
csv -a aVar "$line"
printf "First two columns are: [ '%s' - '%s' ]\n" "${aVar[0]}" "${aVar[1]}"
done <myfile.csv
Dieser Weg ist eindeutig der schnellste und stärkste, als jede andere Kombination von Bash-Builts oder Fork zu irgendeiner Binärdatei zu verwenden.
Unglücklicherweise, abhängig von Ihrer Systemimplementierung, wenn Ihre Version von bash ohne loadable
kompiliert wurde , das funktioniert möglicherweise nicht...
Vollständiges Beispiel mit mehrzeiligen CSV-Feldern.
Hier ist eine kleine Beispieldatei mit 1 Überschrift, 4 Spalten und 3 Reihen. Weil zwei Felder newline enthalten , die Datei ist 6 Zeilenlänge.
Id,Name,Desc,Value
1234,Cpt1023,"Energy counter",34213
2343,Sns2123,"Temperatur sensor
to trigg for alarm",48.4
42,Eye1412,"Solar sensor ""Day /
Night""",12199.21
Und ein kleines Skript, das diese Datei korrekt parsen kann:
#!/bin/bash
enable -f /usr/lib/bash/csv csv
file="sample.csv"
exec {FD}<"$file"
read -ru $FD line
csv -a headline "$line"
printf -v fieldfmt '%-8s: "%%q"\\n' "${headline[@]}"
while read -ru $FD line;do
while csv -a row "$line" ; ((${#row[@]}<${#headline[@]})) ;do
read -ru $FD sline || break
line+=$'\n'"$sline"
done
printf "$fieldfmt\\n" "${row[@]}"
done
Dies kann Folgendes darstellen:(Ich habe printf "%q"
verwendet um nicht druckbare Zeichen wie newlines darzustellen als $'\n'
)
Id : "1234"
Name : "Cpt1023"
Desc : "Energy\ counter"
Value : "34213"
Id : "2343"
Name : "Sns2123"
Desc : "$'Temperatur sensor\nto trigg for alarm'"
Value : "48.4"
Id : "42"
Name : "Eye1412"
Desc : "$'Solar sensor "Day /\nNight"'"
Value : "12199.21"
Dort finden Sie ein vollständig funktionierendes Beispiel:csvsample.sh.txt orcsvsample.sh.
Warnung:
Natürlich ist das Parsen von CSV damit nicht perfekt! Dies funktioniert für viele einfache CSV-Dateien, aber achten Sie auf Codierung und Sicherheit!! Zum Beispiel wird dieses Modul nicht in der Lage sein, binäre Felder zu verarbeiten!
Lesen Sie die Kommentare zum Quellcode von csv.c und RFC 4180 sorgfältig durch!
Wir können CSV-Dateien mit Zeichenfolgen in Anführungszeichen analysieren und beispielsweise durch | trennen 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
zerlegt die Zeichenfolgenfelder in Variablen und tr
entfernt das Anführungszeichen.
Etwas langsamer als awk
wird für jedes Feld ausgeführt.
Von der man
Seite:
-d Trennzeichen Das erste Zeichen von Trennzeichen wird verwendet, um die Eingabezeile abzuschließen, und nicht Zeilenumbruch.
Sie verwenden -d,
wodurch die Eingabezeile mit dem Komma abgeschlossen wird. Der Rest der Zeile wird nicht gelesen. Deshalb ist $y leer.
Sie müssen IFS
verwenden statt -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-Parsing ein spezielles Tool verwenden sollten, das Felder in Anführungszeichen mit internen Kommas verarbeiten kann, neben anderen Problemen, die Bash nicht selbst behandeln kann. Beispiele für solche Tools sind cvstool
und csvkit
.