Comment analyser un fichier CSV dans Bash ?
Arriver en retard à cette question et comme bash offre de nouvelles fonctionnalités, parce que cette question porte sur bash et parce qu'aucune des réponses déjà publiées ne montre cette façon puissante et conforme de faire précisément cela .
Analyse des fichiers CSV sous bash
, en utilisant le module chargeable
Conforme à la RFC 4180 , une chaîne comme cet exemple de ligne CSV :
12,22.45,"Hello, ""man"".","A, b.",42
doit être divisé comme
1 12
2 22.45
3 Hello, "man".
4 A, b.
5 42
bash chargeable Modules compilés en .C.
Sous bash, vous pouvez créer, modifier et utiliser des modules compilés c chargeables . Une fois chargés, ils fonctionnent comme n'importe quel autre intégré !! (Vous pouvez trouver plus d'informations dans l'arborescence source.;)
L'arborescence source actuelle (15 octobre 2021, bash V5.1-rc3) contient un tas d'exemples :
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.
Il existe un cvs
complet qui fonctionne analyseur prêt à l'emploi en examples/loadables
répertoire :csv.c !!
Sous le système basé sur Debian GNU/Linux, vous devrez peut-être installer le paquet bash-builtins par
apt install bash-builtins
Utilisation bash-builtins chargeables :
Ensuite :
enable -f /usr/lib/bash/csv csv
À partir de là, vous pouvez utiliser csv
en tant que bash intégré .
Avec mon échantillon :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
Puis en boucle, traitement d'un fichier.
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
Cette méthode est clairement la plus rapide et la plus puissante que l'utilisation de toute autre combinaison de commandes intégrées bash ou d'un fork vers n'importe quel binaire.
Malheureusement, selon l'implémentation de votre système, si votre version de bash a été compilée sans loadable
, cela peut ne pas fonctionner...
Échantillon complet avec des champs CSV multilignes.
Voici un petit exemple de fichier avec 1 titre, 4 colonnes et 3 Lignes. Parce que deux champs contiennent newline , le fichier est 6 longueur des lignes.
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
Et un petit script capable d'analyser correctement ce fichier :
#!/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
Cela peut rendre :(j'ai utilisé printf "%q"
pour représenter des caractères non imprimables comme newlines comme $'\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"
Vous pouvez y trouver un exemple de travail complet :csvsample.sh.txt orcsvsample.sh.
Avertissement :
Bien sûr, l'analyse CSV à l'aide de this n'est pas parfaite ! Cela fonctionne pour de nombreux fichiers CSV simples, mais attention à l'encodage et à la sécurité !! Par exemple, ce module ne pourra pas gérer les champs binaires !
Lisez attentivement les commentaires du code source csv.c et la RFC 4180 !
Nous pouvons analyser les fichiers csv avec des chaînes entre guillemets et délimités par say | avec le code suivant
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
analyse les champs de chaîne en variables et tr
supprime la citation.
Légèrement plus lent que awk
est exécuté pour chaque champ.
Du man
page :
-d delimLe premier caractère de delim est utilisé pour terminer la ligne d'entrée, plutôt que la nouvelle ligne.
Vous utilisez -d,
qui terminera la ligne d'entrée sur la virgule. Il ne lira pas le reste de la ligne. C'est pourquoi $y est vide.
Vous devez utiliser IFS
au lieu de -d
:
while IFS=, read -r col1 col2
do
echo "I got:$col1|$col2"
done < myfile.csv
Notez que pour une analyse CSV à usage général, vous devez utiliser un outil spécialisé capable de gérer les champs entre guillemets avec des virgules internes, entre autres problèmes que Bash ne peut pas gérer par lui-même. Des exemples de tels outils sont cvstool
et csvkit
.