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 :

Comparer les lignes d'un fichier .csv


Sujet :

Shell et commandes GNU

  1. #1
    Nouveau Candidat au Club
    Technicien Help Desk
    Inscrit en
    Juin 2012
    Messages
    3
    Détails du profil
    Informations professionnelles :
    Activité : Technicien Help Desk
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2012
    Messages : 3
    Points : 1
    Points
    1
    Par défaut Comparer les lignes d'un fichier .csv
    Bonjour,

    Je sollicite votre aide car je ne trouve pas de solution à mon problème.

    J'ai un fichier csv qui contient les données suivantes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    20062012;0810
    20062012;1812
    21062012;0836
    21062012;2035
    Qui correspondent à date;heure

    Je souhaite comparer la premier valeur de la ligne i avec la premier valeur de la ligne i+1 de mon csv.
    Si elles sont identiques, stocker dans un fichier "ligne_i-valeur_1;ligne_i-valeur_2;ligne_i+1-valeur2"

    Voici mon code, je passe en paramètre ($1) le nom de mon fichier csv

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # !/bin/bash
     
    for line in `cat $1`
    do
            if [ `echo $line | awk -F";" '{ print $1 }'` = `echo $(( line+1 )) | awk -F";" '{ print $1 }'` ]; then
     
            DATE=`echo $line | awk -F";" '{ print $1 }'`
            DEBUT=`echo $line | awk -F";" '{ print $2 }'`
            FIN=`echo $(( line+1 )) | awk -F";" '{ print $2 }'`
     
            echo "$DATE;$DEBUT;$FIN" >> ok.txt
            fi
    done
    J'obtiens le retour suivant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    /test.sh: line 7: 20062012;0810: syntax error: invalid arithmetic operator (error token is ";0810")
    ./test.sh: line 7: [: 20062012: unary operator expected
    ./test.sh: line 7: 20062012;1812: syntax error: invalid arithmetic operator (error token is ";1812")
    ./test.sh: line 7: [: 20062012: unary operator expected
    ./test.sh: line 7: 21062012;0836: syntax error: invalid arithmetic operator (error token is ";0836")
    ./test.sh: line 7: [: 21062012: unary operator expected
    ./test.sh: line 7: 21062012;2035: syntax error: invalid arithmetic operator (error token is ";2035")
    ./test.sh: line 7: [: 21062012: unary operator expected
    J'en déduis donc qu'il essaye d'ajouter 1 à l'heure mais j'ai du mal à comprendre pourquoi.

    Merci d'avance

  2. #2
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 587
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 587
    Points : 19 467
    Points
    19 467
    Par défaut
    Bonjour,

    avant tout, regarde comment lire/parser un fichier.

    $(( line+1 )) : $line n'est pas un nombre.

  3. #3
    Expert éminent

    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    1 946
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 1 946
    Points : 6 276
    Points
    6 276
    Par défaut
    Salut,

    Ça me parait un peu lourd comme code

    Une solution avec "sed" (par contre je n'ai pas pris en compte le fait que 2 lignes qui se suivent n'ont pas de correspondance sur le 1er champ).

    Résultat sur la sortie standard (écran) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ cat brol 
    20062012;0810
    20062012;1812
    21062012;0836
    21062012;2035
     
    $ sed -rn 'N;s/([^;]*;)(.*)\n(\1)(.*)/\1\2;\4/p' brol 
    20062012;0810;1812
    21062012;0836;2035
    Résultat dans un fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $ sed -rn 'N;s/([^;]*;)(.*)\n(\1)(.*)/\1\2;\4/w fich' brol 
     
    $ cat fich
    20062012;0810;1812
    21062012;0836;2035
     
    $

  4. #4
    Nouveau Candidat au Club
    Technicien Help Desk
    Inscrit en
    Juin 2012
    Messages
    3
    Détails du profil
    Informations professionnelles :
    Activité : Technicien Help Desk
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2012
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Citation Envoyé par N_BaH Voir le message
    Bonjour,

    avant tout, regarde comment lire/parser un fichier.

    $(( line+1 )) : $line n'est pas un nombre.
    Merci pour ce petit tuto, ca va me servir pour la suite


    Citation Envoyé par zipe31 Voir le message
    Salut,

    Ça me parait un peu lourd comme code

    Une solution avec "sed" (par contre je n'ai pas pris en compte le fait que 2 lignes qui se suivent n'ont pas de correspondance sur le 1er champ).

    Résultat sur la sortie standard (écran) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ cat brol 
    20062012;0810
    20062012;1812
    21062012;0836
    21062012;2035
     
    $ sed -rn 'N;s/([^;]*;)(.*)\n(\1)(.*)/\1\2;\4/p' brol 
    20062012;0810;1812
    21062012;0836;2035
    Résultat dans un fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $ sed -rn 'N;s/([^;]*;)(.*)\n(\1)(.*)/\1\2;\4/w fich' brol 
     
    $ cat fich
    20062012;0810;1812
    21062012;0836;2035
     
    $
    Je connais pas vraiment "sed" je vais me documenter un peu sur la chose, mais à ce que tu me dit,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sed -rn 'N;s/([^;]*;)(.*)\n(\1)(.*)/\1\2;\4/p' brol
    ne s'applique qu'au fichier qui contient 4 lignes?


    Pour faire simple, je travaille en horaire décaler, mon profil et celui de mes collègues (total 3 personnes) est unique dans la société, la badgeuse ne peut connaitre notre planning car il est different chaque semaine, on est donc obliger de calculer nos horaire nous meme. On est parvenu à extraire du logiciel de badge un fichier csv qui contient la date et l'heure du pointage.
    Pour un journée, on a donc 2 lignes (debut et fin) si je traite mes pointages correctement tous les mois, le fichier contiendra environ 60 lignes par mois, mais si j'oublie de le faire, comme ces derniers temps, il peut contenir jusqu'à 360 lignes... et oui 5mois de retard ca fait beaucoup...

  5. #5
    Expert éminent

    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    1 946
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 1 946
    Points : 6 276
    Points
    6 276
    Par défaut
    mais à ce que tu me dit, ne s'applique qu'au fichier qui contient 4 lignes?
    Non, peu importe le nombre de lignes, d'autant plus avec ce que tu viens de rajouter, à savoir :
    Pour un journée, on a donc 2 lignes (debut et fin)
    Si les lignes vont de paire, alors no soucy

    Attention toutefois à ce que le format (fin de ligne) du csv soit bien de l'Unix et non du Windows.

  6. #6
    Nouveau Candidat au Club
    Technicien Help Desk
    Inscrit en
    Juin 2012
    Messages
    3
    Détails du profil
    Informations professionnelles :
    Activité : Technicien Help Desk
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2012
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Est ce que tu peut m'expliquer les paramètre que tu a renseigner derrière "sed -rn" parceque j'ai du mal a comprend. je vois bien le principe du "sed s/avant/apres/" mais pas le contenu.

    merci

  7. #7
    Expert éminent

    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    1 946
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 1 946
    Points : 6 276
    Points
    6 276
    Par défaut
    -rn
    r pour utiliser la syntaxe des expressions régulières étendues et ne pas avoir à protéger certains caractères, comme les parenhèses car ça devient vite imbuvable
    n pour empêcher l'écriture sur la sortie standard. En association avec le flag "p", permet de n'afficher que ce qu'on veut.


    N
    Ajoute la ligne suivante dans l'espace de travail de sed. Sed étant un éditeur de flux, il lit chaque ligne (ou flux) une par une dans sa mémoire principale, la traite et la renvoie sur la sortie standard (je schématise), puis vide sa mémoire et lit le flux suivant. Donc la commande "N" permet d'ajouter la ligne suivante dans l'espace de travail et de traiter son contenu. Chaque ligne ajoutée est séparée par le caractère de fin de ligne "\n".


    s/([^;]*;)(.*)\n(\1)(.*)/\1\2;\4/w fich
    La commande de substitution, "s/motif/remplacement/" pour un usage plus généralement employé.
    Par contre ici on délimite dans la partie "motif", chaque occurrence ou champ par des sous-expressions (encadrées par des parenthèses), qui seront réutilisées dans la partie remplacement par leur pendant appelés "références arrières" qui sont désignées par un numéro correspondant à son ordre d'apparition dans l'expression régulière.
    En ayant donc un espace de travail, après ajout de la ligne suivante) qui ressemble à 20062012;0810;1812\n21062012;0836;2035.

    La 1ère "([^;]*;)" englobe tout jusqu'à ce qu'elle rencontre un ";", donc la date et le ";" qui suit : 20062012;
    La 2nde "(.*)\n" englobe tout jusqu'au caractère saut de ligne (\n) non inclue dans la sous-expression : 0810;1812
    La 3ème "(\1)" est en fait une référence arrière qui reprend le contenu de la 1ère sous-expression, ce qui permet de vérifier donc que les 2 dates sont bien les mêmes : 20062012;
    Et la dernière "(.*)" englobe tout ce qui reste sur la ligne : 0836;2035

    /\1\2;\4/
    Dans la partie droite de la syntaxe de substitution on se contente de mettre les références arrières que l'on veut afficher.
    La 1ère, suivie de la seconde, suivie d'un ";" et de la 4ème. Au passage le caractère fin de ligne (\n) est passé à la trappe.

    w fich
    La commande "w" (write) quant à elle permet d'écrire chaque substitution dans un fichier.

Discussions similaires

  1. Compter les lignes d'un fichier CSV à partir d'une ligne
    Par miniRoshan dans le forum Général Java
    Réponses: 6
    Dernier message: 03/06/2010, 11h16
  2. Réponses: 4
    Dernier message: 02/06/2010, 17h23
  3. comparer les lignes d'un fichier
    Par smartmobili dans le forum Général Python
    Réponses: 9
    Dernier message: 24/02/2010, 11h15
  4. Comparer les lignes d'un fichier txt
    Par Casimir* dans le forum VBScript
    Réponses: 3
    Dernier message: 28/08/2007, 15h12
  5. [CSV] Compter les lignes d’un fichier csv
    Par sam01 dans le forum Langage
    Réponses: 3
    Dernier message: 24/01/2007, 11h16

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