Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#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

percherie #7 a écrit :

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 pieces

SYNOPSIS
       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