IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes GNU Discussion :

Division d'un fichier csv et nouveaux champs


Sujet :

Shell et commandes GNU

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 21
    Par défaut Division d'un fichier csv et nouveaux champs
    Bonjour à tous,
    J'ai fait un script php pour l'upload d'une base de données. Seulement après avoir eu connaissance de la taille de la base à insérer (par fichiers csv de 160 000 lignes) j'ai vite compris que le serveur allait être dépassé par les commandes lourdes (allocation d'un tableau, etc...).
    J'ai donc décidé de faire les mêmes opérations en commandes linux mais hélas je ne les connais pas du tout et donc je risque de faire quelque chose de très mal optimisé, c'est pourquoi je me tourne vers vous.

    Shéma du fichier csv de départ :
    FICHIER RAPPORT;champ2;champ3;
    FICHIER TYPE2;champ2;champ3;champ4;
    FICHIER TYPE3;champ2,;champ3;champ4;champs5;
    FICHIER TYPE4;champ2,;champ3;champ4;champs5;

    Deux choses doivent être faites :

    -Isoler chaque type de de ligne (FICHIER RAPPORT, FICHIER TYPE2...) dans d'autres fichiers csv (s'appellant par exemple "rapport.csv","type2.csv"...)

    -Ajouter deux champs à la fin de chaque ligne (le mois et l'année) dans chacun de ces fichiers.

    La première opération je ne trouve pas vraiment comment la faire efficacement.
    La deuxième est bien plus simple mais je ne sais pas ce qui serait le plus optimisé.


    Merci d'avance de votre aide.

  2. #2
    Rédacteur/Modérateur
    Avatar de Winnt
    Homme Profil pro
    budget et contrôle de gestion
    Inscrit en
    Décembre 2006
    Messages
    1 978
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France

    Informations professionnelles :
    Activité : budget et contrôle de gestion
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 978
    Par défaut
    Salut,

    Pour générer tes fichiers :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    sed -n "/RAPPORT/p" fichier_csv_depart > rapport.csv
    sed -n "/TYPE2/p" fichier_csv_depart > type2.csv
    sed -n "/TYPE3/p" fichier_csv_depart > type2.csv
    sed -n "/TYPE4/p" fichier_csv_depart > type2.csv
    Winnt
    Merci de lire les règles du forum LaTeX et Qu'est ce qu'un ECM ?.
    N'hésitez pas à parcourir la FAQ la réponse y est peut-être déjà.
    Pensez au bouton si votre problème est résolu.


    C'est en Linuxant qu'on devient .... geek
    Et c'est en LateXant qu'on devient flemmard
    Mon blog tout neuf.
    Articles : présentation de la distribution Gentoo, Les index sous LaTeX et leur personnalisation.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 21
    Par défaut
    Merci beaucoup c'est parfait.
    Et pour rajouter par exemple "08;2009;" à la fin de chaque ligne quel est le plus efficace? utiliser awk?

    Sinon il peut arriver que dans le ficher csv de départ il y ai à la fin d'une ligne plein de ;;;;;;;; (car il y a des cases vides dans le fichier de départ), est-il possible de rajouter le "08;2009;" tout en retirant les ";" en trop avant? (donc en n'en gardant qu'un).

    En reprenant l'exemple :
    FICHIER RAPPORT;champ2;champ3;;;;;;;;;

    le remplacer par :
    FICHIER RAPPORT;champ2;champ3;08;2009;

  4. #4
    Membre expérimenté
    Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2007
    Messages
    248
    Détails du profil
    Informations personnelles :
    Âge : 73
    Localisation : France

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2007
    Messages : 248
    Par défaut
    Si tu dois faire des traitements particulier, il y deux possibilités:
    1) utilisé sed avec des expressions regulières parenthèsées qui permettent de faire un epu de traitement
    2) utiliser awk qui permet de faire des traitements complexes.

    Personnellement j'ai eu a faire la même chose une fois, je préfère awk

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 21
    Par défaut
    N'ayant pas vu ta réponse je me suis tourné vers du sed avec :
    sed 's/$/08\/2009;/' <titi.csv> tata.csv pour l'ajout.
    Une meilleure idée?

    Pour les ;;;;; en trop ça ne peut se produire que sur un petit fichier (pas celui avec des centaines de milliers de lignes) donc je peux le faire à part mais j'aurais bien voulu trouver une astuce.

    Peut être avec un "remplacement" de tous les ;;;; quel que soit leur nombre à la fin du fichier par ;08/2009; . Mais d'une part ça peut peut être devenir lourd? et d'autre part je dois réviser mes expressions réguliaires pour pouvoir le faire

  6. #6
    Invité
    Invité(e)
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    echo "FICHIER RAPPORT;champ2;champ3;;;
    FICHIER TYPE2;champ2;champ3;champ4;;
    FICHIER TYPE3;champ2,;champ3;champ4;champs5;
    FICHIER TYPE4;champ2,;champ3;champ4;champs5;" | sed -n 's/;*$/;08;2009;/
    /RAPPORT/wrapport.csv
    /TYPE2/wtype2.csv'
    cat rapport.csv
    FICHIER RAPPORT;champ2;champ3;08;2009;
    cat type2.csv
    FICHIER TYPE2;champ2;champ3;champ4;08;2009;
    /!\ les alinéas sont essentiels dans la commande sed.

  7. #7
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    792
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 792
    Par défaut
    Pour le traitement des gros fichiers, donner la préférence à une seule invocation d'un éditeur de ligne (sed ou awk). Awk me semblant plus approprié et lisible pour ce genre de traitement. En une seule passe, le code suivant va se débarrasser des multiples ; de fin de ligne et ensuite éclater les lignes dans leur sous-fichier. Le fichier de départ n'est parcouru qu'une seule fois ce qui devrait assurer un gain de temps important par rapport à plusieurs sed en série.

    dans un fichier, par exple: eclatement.awk
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    # remplacement des ; multiples en fin de ligne
    /;+$/ {$0=gensub(/;+$/, "", $0)}
     
    # éclatement du fichier et rajout de 08/2009
    /FICHIER RAPPORT/ {print $0";08;2009;" >"/tmp/fichier1"}
    /FICHIER TYPE2/ {print $0";08;2009;" >"/tmp/fichier2"}
    /FICHIER TYPE3/ {print $0";08;2009;" >"/tmp/fichier3"}
    /FICHIER TYPE4/ {print $0";08;2009;" >"/tmp/fichier4"}
    ou bien

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    # remplacement des ; multiples en fin de ligne
    /;+$/ {$0=gensub(/;+$/, ";08;2009;", $0)}
     
    # éclatement du fichier et rajout de 08/2009
    /FICHIER RAPPORT/ {print >"/tmp/fichier1"}
    /FICHIER TYPE2/ {print  >"/tmp/fichier2"}
    /FICHIER TYPE3/ {print  >"/tmp/fichier3"}
    /FICHIER TYPE4/ {print  >"/tmp/fichier4"}
    Ensuite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    # awk -f eclatement.awk fichier-a-traiter

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 21
    Par défaut
    Très bien, merci beaucoup à vous tous.
    Je suis partit sur du sed et c'est pour l'instant largement assez rapide (environ 5 secondes pour le tout contre 45 minutes avant...).

    Pour ta solution ripat je l'aurais bien utilisé sauf que la demande a un peu changé : il faut finalement que je supprime le champ avec "FICHIER ..." car inutile étant donné qu'ils vont se retrouver dans des tables différentes.
    Donc du coup je suis obligé de faire le traitement après coup dans chaque fichier et c'est donc impossible de tout faire en une commande. A moins que je me trompe?

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 21
    Par défaut
    Je continue sur ce sujet même si mon problème est un peu différent ici.

    Je souhaite maintenant récupérer un champ d'un csv format heure de type 10:02:56 (10h 02 minutes 56 secondes), ce que je fais facilement, mais ensuite extraire dans le même temps l'heure, les minutes et les secondes, pour y faire une manip et l'insérer dans le "grand" csv à la place du champ précédent. Comment ça je suis tordu

    Bon comme c'est pas bien clair petit exemple :
    champ1;champ2;champ3;10:02:56;champ5
    champ1;champ2;champ3;09:36:45;champ5
    champ1;champ2;champ3;02:64:36;champ5
    champ1;champ2;champ3;11:24:56;champ5

    je veux arriver à :
    champ1;champ2;champ3;10+02+56;champ5
    champ1;champ2;champ3;09+36+45;champ5
    champ1;champ2;champ3;02+64+36;champ5
    champ1;champ2;champ3;11+24+56;champ5

    (10+02+56 étant bien entendu une addition).

    Je suis parti sur du awk mais je ne vois pas comment en mettre un dans un autre.

    La seule solution que je vois pour l'instant est un truc du genre:
    awk -F ";" '{print $4}' fichier1 > fichier2
    awk -F ":" '{print $1+$2+$3}' fichier2 > fichier3

    Et après mettre le contenu du fichier 3 dans le fichier 1.
    Mais d'une part je ne vois pas comment le faire, et d'autre par je suis sur qu'il y a bien plus simple.

    Please help j'en peux plus

  10. #10
    Membre émérite Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Par défaut
    Bonjour,

    Voudrais-tu dire que tu veux changer les ':' par '+' dans le quatrième champ?

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 21
    Par défaut
    Non je voudrais faire l'addition (ou plus précisément le nombre de secondes à la place de l'heure, soit h*3600+m*60+s) à la place de l'heure telle qu'elle est écrite au départ.

  12. #12
    Membre émérite Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Par défaut
    Ha, Okay, okay, okay. Bah alors c'est quelque chose comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk -F ';' '{split($4, t, ":"); $4=t[1]*3600+t[2]*60+t[3]; print}' file_in > file_out

  13. #13
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 21
    Par défaut
    Merci beaucoup, parfait(j'ai l'impression de me répéter dans ce topic

  14. #14
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    792
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 792
    Par défaut
    Variante avec une regex comme FS:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk -F';|:' '{$8=$4*3600+$5*60+$6}1' fichier > fichier_sortie
    Attention pour les (très) gros fichiers, l'utilisation de regex comme FS peut s'avérer plus gourmand.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 26/06/2012, 11h34
  2. Réponses: 11
    Dernier message: 27/10/2008, 09h15
  3. [CSV] Modifier un champ d'un fichier CSV
    Par BernardT dans le forum Langage
    Réponses: 3
    Dernier message: 04/07/2007, 10h13
  4. Réponses: 3
    Dernier message: 11/06/2007, 11h20
  5. Réponses: 3
    Dernier message: 26/04/2006, 11h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo