#1 Le 25/07/2014, à 20:32
- percherie
Améliorer mon script de découpage de CSV
Bonsoir,
Je doit manipuler un gros CSV et pour garder la main, au lieu de faire ça à la main je tente un petit script. J'arrive d'un coté à découper le fichier toute les 10.000 ligne mais concernant un tris alphabétique en amont, je souhaite que la première ligne reste en place (titre des colonne dans un tableur)
bash decoupage.sh <fichier.csv> <nom_en_sortie>
Dans ce code, on peut définir un nom pour le fichier de sortie mais ça coince si je n'en défini aucun. Comment faire en sorte d'utiliser un nom de remplacement défini dans le code si aucun n'est choisi ? Comment placer la première ligne du fichier d'origine sur chaque fichier splité (sauf le premier) ?
#!/usr/bin/sh
split -l 10000 "$1" $2_
for i in $2* ; do mv $i $i.csv ; done
Dans ce code, le tris fonctionne très bien mais je souhaite ignorer la première ligne. Je pensait extraire son contenu, la supprimer du fichier, faire le tris et l'ajouter au début du fichier. C'est une usine à gaz. Peut être qu'une commande permet à "sort" d'ignorer la première ligne ?
cat fichier.csv | sort -t "," -k1n,1n > test.csv
Voilou, mon fichier d'origine n'est pas si énorme (300 mille entrées) mais c'est l'occasion de pratiquer un peut plus le bash ;-)
Nomade en camion utilisant Ubuntu. Si vous souhaitez suivre mes voyages : http://toutenkamion.net/
Hors ligne
#2 Le 25/07/2014, à 21:28
- pingouinux
Re : Améliorer mon script de découpage de CSV
Bonsoir,
Voici une suggestion, mais je n'ai pas trouvé de solution miracle…
#!/bin/bash
lig1=$(head -1 "$1")
tail -n +2 "$1" >/tmp/reste
dest=${2:-defaut} # La variable dest vaut $2 si défini, defaut sinon
sort -t, -k1n,1 /tmp/reste >/tmp/test.csv
split -l 10000 /tmp/test.csv "$dest"
for i in "$dest"*
do
echo "$lig1" >"$i".csv
cat "$i" >>"$i".csv
rm "$i"
done
Édité : On peut simplifier
#!/bin/bash
lig1=$(head -1 "$1")
dest=${2:-defaut} # La variable dest vaut $2 si défini, defaut sinon
tail -n +2 "$1" | sort -t, -k1n,1 | split -l 10000 - "$dest"
for i in "$dest"*
do
echo "$lig1" >"$i".csv
cat "$i" >>"$i".csv
rm "$i"
done
Dernière modification par pingouinux (Le 25/07/2014, à 21:47)
Hors ligne
#3 Le 26/07/2014, à 05:17
- percherie
Re : Améliorer mon script de découpage de CSV
merci je me serait orienté naturellement vers la solution 1 sans penser à utiliser le répertoire tmp mais l'utilisation des pipe est vraiment plus chouette.
ça me fait pas mal de petite chose à consulter sur le man, c'est intéressant comme solution.
Nomade en camion utilisant Ubuntu. Si vous souhaitez suivre mes voyages : http://toutenkamion.net/
Hors ligne
#4 Le 26/07/2014, à 07:26
- pingouinux
Re : Améliorer mon script de découpage de CSV
Tu peux regarder la rubrique Parameter Expansion dans.man bash. Tu y trouveras l'explication pour la syntaxe de dest=${2:-defaut}, ainsi que de nombreux autres trucs intéressants.
Hors ligne
#5 Le 26/07/2014, à 07:37
- Watael
Re : Améliorer mon script de découpage de CSV
salu,
je ferais bien un bête sed, plutôt qu'un lourd for:
read ligne1 < fichierOrig
sed -si '1i'"$ligne1" "$dest"*
Connected \o/
Welcome to sHell. · eval is evil.
Hors ligne
#6 Le 26/07/2014, à 07:51
- pingouinux
Re : Améliorer mon script de découpage de CSV
@Watael : Effectivement, c'est beaucoup mieux
Hors ligne
#7 Le 31/07/2014, à 14:52
- percherie
Re : Améliorer mon script de découpage de CSV
Merci à vous deux. J'ai découvert les commandes head et tail. c'est pas mal du tout. Par contre je n'ai pas compris la syntaxe en fin de pipe. Pourquoi le tiret présent juste avant la variable $destination permet de définir le résultat précédent sur la fonction split ?
Voici mon script commenté au passage
#!/bin/bash
# Récupération de la première ligne du fichier indiqué en entrée
ligne1=$(head -1 "$1")
# La variable destination vaut $2 si défini en seconde entrée, "split" autrement
destination=${2:-split}
# Lecture à partir 2° ligne | tris croisant de la première colonne, fin à la première | découpage toute les N ligne et enregistrement dans $destination
tail -n +2 "$1" | sort -t, -k1n,1n | split -l 1000 - "$destination"_
# Insertion de la 1er ligne du fichier source sur tous les fichier $destination
sed -si '1i'"$ligne1" "$destination"*
# Ajouter l'extension .csv sur les fichier découpés
for i in $destination* ; do mv $i $i.csv ; done
J'ai tenté de remplacer la dernière boucle for dans le pipe mais sans résulta.
Nomade en camion utilisant Ubuntu. Si vous souhaitez suivre mes voyages : http://toutenkamion.net/
Hors ligne
#8 Le 31/07/2014, à 16:43
- pingouinux
Re : Améliorer mon script de découpage de CSV
Par contre je n'ai pas compris la syntaxe en fin de pipe. Pourquoi le tiret présent juste avant la variable $destination permet de définir le résultat précédent sur la fonction split ?
Si le nom du fichier est remplacé par -, split lit l'entrée standard.
Voici le début de man split
NAME
split - split a file into piecesSYNOPSIS
split [OPTION]... [INPUT [PREFIX]]DESCRIPTION
Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default size is 1000 lines,
and default PREFIX is `x'. With no INPUT, or when INPUT is -, read standard input.
Il est aussi prudent de remplacer la dernière ligne par :
for i in "$destination"* ; do mv "$i" "$i".csv ; done
Hors ligne
#9 Le 31/07/2014, à 17:40
- percherie
Re : Améliorer mon script de découpage de CSV
Merci je comprend mieux pour split... concernant les doc en anglais il me faut la pierre de rosette pour m'en sortir mais avec le temps j'arrive de mieux en mieux à déchiffrer l'anglais informatique (je trouve plus simple que l'anglais basique)
Nomade en camion utilisant Ubuntu. Si vous souhaitez suivre mes voyages : http://toutenkamion.net/
Hors ligne