GNU/Linux >> Znalost Linux >  >> Linux

Jak analyzovat soubor CSV v Bash?

Jak analyzovat soubor CSV v Bash?

Přicházíme pozdě na tuto otázku a bash nabízí nové funkce, protože tato otázka se týká bash a protože žádná z již zveřejněných odpovědí neukazuje tento účinný a vyhovující způsob, jak udělat přesně toto .

Analýza souborů CSV pod bash pomocí zaváděcího modulu

Vyhovuje RFC 4180 , řetězec jako tento ukázkový řádek CSV :

12,22.45,"Hello, ""man"".","A, b.",42

by měl být rozdělen jako

 1  12
 2  22.45
 3  Hello, "man".
 4  A, b.
 5  42

bash lze načíst .C kompilované moduly.

V bash můžete vytvářet, upravovat a používat načítatelné c kompilované moduly . Po načtení fungují jako každá jiná budova !! (Více informací můžete najít ve zdrojovém stromu.;)

Aktuální zdrojový strom (15. října 2021, bash V5.1-rc3) obsahuje spoustu ukázek:

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.

K dispozici je plně funkční cvs analyzátor připraven k použití v examples/loadables adresář:csv.c !!

V systému založeném na Debian GNU/Linux budete možná muset nainstalovat balíček bash-builtins pomocí

apt install bash-builtins

Použití načítatelných bash-builtinů :

Potom:

enable -f /usr/lib/bash/csv csv

Odtud můžete použít csv jako vestavěný bash .

S mým vzorem: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

Poté ve smyčce zpracování souboru.

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

Tento způsob je jednoznačně nejrychlejší a nejsilnější než použití jakékoli jiné kombinace vestavěných bash nebo forku k libovolnému binárnímu systému.

Bohužel, v závislosti na implementaci vašeho systému, pokud vaše verze bash byla zkompilována bez loadable , to nemusí fungovat...

Úplný vzorek s víceřádkovými poli CSV.

Zde je malý ukázkový soubor s 1 nadpis, 4 sloupce a 3 řádky. Protože dvě pole obsahují nový řádek , soubor je 6 délka řádků.

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

A malý skript schopný správně analyzovat tento soubor:

#!/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

To může vykreslit:(Použil jsem printf "%q" reprezentovat netisknutelné znaky jako nové řádky jako $'\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"

Úplnou pracovní ukázku můžete najít zde:csvsample.sh.txt nebo csvsample.sh.

Upozornění:

Parsování CSV pomocí tohoto samozřejmě není dokonalé! Toto funguje pro mnoho jednoduchých souborů CSV, ale postarejte se o kódování a zabezpečení! Například tento modul nebude schopen zpracovat binární pole!

Přečtěte si pozorně komentáře ke zdrojovému kódu csv.c a RFC 4180!


Můžeme analyzovat soubory csv s řetězci v uvozovkách a oddělenými řekněme | s následujícím kódem

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 analyzuje pole řetězců na proměnné a tr odstraní nabídku.

O něco pomalejší než awk se provede pro každé pole.


Z man stránka:

-d delimPrvní znak delim se používá k ukončení vstupního řádku, nikoli nový řádek.

Používáte -d, která ukončí vstupní řádek na čárce. Nepřečte zbytek řádku. Proto je $y prázdné.


Musíte použít IFS místo -d :

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

Všimněte si, že pro obecnou analýzu CSV byste měli použít specializovaný nástroj, který dokáže zpracovat pole v uvozovkách s vnitřními čárkami, mimo jiné problémy, které Bash sám nezvládne. Příklady takových nástrojů jsou cvstool a csvkit .


Linux
  1. Jak normalizujete cestu k souboru v Bash?

  2. Jak zvýraznit Bash skripty ve Vimu?

  3. Jak grep \nv souboru

  1. Jak zkontrolovat syslog v Bash na Linuxu?

  2. Jak analyzovat hlavičky HTTP pomocí Bash?

  3. Jak uchovám historii bash napříč relacemi?

  1. Jak zkontrolovat, zda je soubor prázdný v Bash?

  2. Jak zahrnout soubor do skriptu bash shell

  3. Jak získám absolutní adresář souboru v bash?