GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie parse ich eine CSV-Datei in Bash?

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

installieren
apt 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 .


Linux
  1. Wie normalisiert man einen Dateipfad in Bash?

  2. Wie überprüfe ich Syslog in Bash unter Linux?

  3. Wie überprüfe ich, ob eine Datei in Bash leer ist?

  4. So schließen Sie eine Datei in ein Bash-Shell-Skript ein

  5. Wie erhalte ich das absolute Verzeichnis einer Datei in Bash?

So überprüfen Sie, ob eine Datei oder ein Verzeichnis in Bash vorhanden ist

So lesen Sie eine Datei Zeile für Zeile in Bash

So leiten Sie stderr in Bash auf stdout um

So verwenden Sie Bash-Dateitestoperatoren in Linux

So analysieren Sie CSV-Dateien in Bash-Skripten unter Linux

So überprüfen Sie, ob eine Datei oder ein Verzeichnis in der Bash-Shell vorhanden ist