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

Linux Discussion :

sed et boucle pour pour supprimer des lignes


Sujet :

Linux

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 23
    Points : 11
    Points
    11
    Par défaut sed et boucle pour pour supprimer des lignes
    Bonjour,

    J'ai un problème que je n'arrive pas à trouver sous la ligne de commande.
    Alors voilà je dois supprimer des lignes dans un fichier clients en me référant à une base interdite. Je pensais tenir le bon bout mais je suis en traine de me noyer.

    Admettons que j'ai un fichier client comme ceci (séparation par des ; ):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    CLIENT1;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT2;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT3;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT4;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT5;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT6;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT7;NOM PRENOM;ADRESSE;CODE;VILLE
    avec un fichier interdit (le code du client avec un ; ):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    CLIENT2;
    CLIENT3;
    CLIENT6;
    Je veux avoir comme résultat:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    CLIENT1;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT4;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT5;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT7;NOM PRENOM;ADRESSE;CODE;VILLE
    et donc supprimer les occurences correspondantes trouver dans le fichier intedit.

    Sous bash j'essaye de faire ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    for i in `cat interdit.txt`; do sed -i "/^$i/d" Clients.txt; done;
    Bon ça ne marche pas vraiment. Je ne sais pas pourquoi pas tous les codes clients commençant par A sont supprimés alors qu'il devrait en rester. En plus c'est très long (bon ok il y a 200 000 clients...)

    Rem1: Je n'arrive pas à faire la négation dans les options de sed ce qui me permettrai de me baser en fait que sur les bons codes et éviter de sortir une base interdite.

    Rem2: Je me demande s'il n'y a pas de prob avec le $ qui est un opérande particulier sous sed... C'est pour ça que j'ai mis entre " "

    Rem3: Je ne sais si c'est aussi possible de dire à sed de s'arrêter une fois la ligne supprimée car comme c'est une base client ben tous les codes sont différents... et çe me ferais gagner du temps.

    Rem4: Le code client est sur 6 caractères alpha mais ne prend pas forcément tous les caractères (par AA1 , CCC88 , AB , AZREKK).

    Rem5: Dans ma base interdite j'ai rajouté en fin de ligne pour chaque code un point virgule pour me faciliter la vie dans les comparaisons sinon j'avais encore plus de bordel. Donc il cherche le code client plus ;

    Rem6: ça commence toujours par le code direct d'où le ^

    Vous pouvez m'aider? Je me demande s'il ne faut pas que le fasse avec perl dans un plus gros prog.

  2. #2
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 23
    Points : 11
    Points
    11
    Par défaut
    Rem7: le code client peut contenir des points à la suite ou pas (A.DRE. ou A..RF1) des apostrophes( L'ERMO ), des tirets (DU-CLI)

  3. #3
    LLB
    LLB est déconnecté
    Membre expérimenté
    Inscrit en
    Mars 2002
    Messages
    967
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 967
    Points : 1 410
    Points
    1 410
    Par défaut
    R1 : c'est ! (à mettre après le sélecteur de lignes)

    R2 : Non ! C'est le shell qui fait l'expansion de $i. Sed ne connait pas (pour t'en convaincre, remplace sed par echo).

    R3 : Oui. C'est la commande q.


    Comme tu parles d'optimisation, pourrais-tu donner les ordres de grandeurs (nombre de lignes) pour les 2 fichiers ?

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 23
    Points : 11
    Points
    11
    Par défaut
    j'ai déjà essayé avec ! mais ça me jette. Je n'ai pas du le placer au bon endroit surement. Je vais revoir ça.

    C'est ce que j'ai fait pour $i. Comme ça ne marchait pas j'ai fait un echo en boucle pour voir ce que me donné
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    for i in `cat interdit.txt`; do echo "$i"; done
    bon pas de prob forcément puis après j'ai voulu rajouter un ; en plus et là ça m'inverse les champs. $i est évalué après l'affichage de ;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    for i in `cat interdit.txt`; do echo "$i;"; done
    va me donner
    ;CLIENT1
    ;CLIENT2
    ...
    et donc c'est pour ça que j'ai intégré directement le ; dans le fichier interdit. Bon c'est pas ça le plus important.

    Base de grandeur:
    fichier clients: 200 000 lignes
    fichier intedit: 198 000 lignes
    ==> il n'y a donc que 2000 clients à garder... tu vois pourquoi je voudrai utiliser la négation.

  5. #5
    LLB
    LLB est déconnecté
    Membre expérimenté
    Inscrit en
    Mars 2002
    Messages
    967
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 967
    Points : 1 410
    Points
    1 410
    Par défaut
    OK.

    Pour sed :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    sed "/^$i/!d"
    sed -n "/^$i/p"

    Puisque les fichiers sont gros, évite absolument de faire `cat ...`. Tout le fichier est chargé en mémoire avant de faire quoi que ce soit d'autre.

    Niveau algo : tu cherches à parcourir le 2e fichier pour chaque ligne du 1er fichier. D'où, complexité quadratique.

    Si tes fichiers sont triés, tu peux lire les deux fichiers en même temps (complexité linéaire) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    exec < fichier2
    exec 6<&0
    exec < fichier1
    while read line; do
        echo "1: $line"
        read line2 <&6
        echo "2: $line2"
    done
    Ca devrait t'aider...

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 23
    Points : 11
    Points
    11
    Par défaut
    merdi du coup de main mais...

    le ! avant le d j'avais déjà essayé et ça ne passe pas:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    bash: !d": event not found

  7. #7
    LLB
    LLB est déconnecté
    Membre expérimenté
    Inscrit en
    Mars 2002
    Messages
    967
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 967
    Points : 1 410
    Points
    1 410
    Par défaut
    Et si tu lisais le message d'erreur... ?

    C'est pas un problème de sed, mais du shell. Utilise des simples quotes.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 23
    Points : 11
    Points
    11
    Par défaut
    oui mais je n'ai plus d'évaluation de $i si je prends des simples quote...ou peut être faut il les combiner mais j'ai beau essayer ça ne marche pas.

  9. #9
    LLB
    LLB est déconnecté
    Membre expérimenté
    Inscrit en
    Mars 2002
    Messages
    967
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 967
    Points : 1 410
    Points
    1 410
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    sed "/^$i/"'!d'
    sed -n "/^$i/p" # tu pouvais utiliser cette variante, aussi...
    Et sinon, ma solution en shell ne te convient pas ?

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 23
    Points : 11
    Points
    11
    Par défaut
    je commene a plus trop savoir ce que je fais pfffffff... ça m'avait l'air simple et j'y perds mon latin...

    Bon oui avec les quots comme ça pas d'erreur (je me demande comment j'y ai pas pensé.) mais ça marche avec le sed sans le -i si je mets le -i avec la négation je n'ai plus rien (alors que sans le ! c'est bon).
    (Je fais des tests avec les exemples que j'ai donné pour aller plus vite)

    Pour ta solution, comme je n'ai pas l'habitude d"utiliser ça ben je préfère ne pas m'y pencher pour l'instant mais merci bien entendu je le mets dans un coin pour voir après.
    Sérieusement je ne vois pas pourquoi ça merdouille comme ça.

  11. #11
    LLB
    LLB est déconnecté
    Membre expérimenté
    Inscrit en
    Mars 2002
    Messages
    967
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 967
    Points : 1 410
    Points
    1 410
    Par défaut
    Bon allez...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while read line; do grep -q "$line" interdits || echo "$line"; done < clients
    (et adapte l'expression rationnelle)
    Pour sélectionner des lignes, grep est plus approprié que sed.
    Pour parcourir un fichier, while est plus approprié que for.
    L'option -q de grep permet d'optimiser et de quitter dès que la ligne a été trouvée.

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 23
    Points : 11
    Points
    11
    Par défaut
    bon j'ai compris pourquoi il me donne un fichier vide avec le ! ... forcément ce n'est pas la bonne méthode car il m'efface direct toutes les lignes sauf une puis second passage il le rend vide. Donc avec ma méthode je suis obligé de ne pas prendre le !

    Ce qui est bizarre c'est que avec l'exmple que j'ai donné plus de prob mais dès que je prends mon vrai fichier c'est le bordel. C'est pour ça que je me demandais aussi si un caractère dans le champs du code client ne pouvait pas interférer avec la ligne de code lors de l'évaluation.

    je vais devenir fou

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 23
    Points : 11
    Points
    11
    Par défaut
    j'essaye ta soluce pour voir.

  14. #14
    Membre éclairé Avatar de BlaireauOne
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    492
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mars 2007
    Messages : 492
    Points : 652
    Points
    652
    Par défaut
    liste.txt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    CLIENT1;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT2;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT3;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT4;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT5;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT6;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT7;NOM PRENOM;ADRESSE;CODE;VILLE
    interdit.txt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CLIENT2;
    CLIENT3;
    CLIENT6;
    Commande "join" :

    -v numéro
    Afficher sur la sortie standard, à la place du résultat habituel, une ligne pour chaque ligne du fichier numéro (1 ou 2), qui ne peut pas être appariée.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    join -t";" -v 1 liste.txt interdit.txt
    Résultat

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    CLIENT1;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT4;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT5;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT7;NOM PRENOM;ADRESSE;CODE;VILLE

  15. #15
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 23
    Points : 11
    Points
    11
    Par défaut
    Bon merci à tous.

    Donc ça marche. Je vais voir avec join aussi (p'tain les boules... connaissez pas)

    Sinon:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    cat mailing.sh
     
    #!/bin/bash
    while read line
    do
    temp=`grep "^$line" $2`
    echo $temp >> $3
    done < $1
    Utilisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ./mailing.sh ClientsStat.txt Clients.txt Mailing.txt
    rem: mon fichier client_interdit et devenu en fait client_ok car plus rapide à traiter forcément.

  16. #16
    Membre régulier
    Inscrit en
    Juillet 2002
    Messages
    168
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 168
    Points : 110
    Points
    110
    Par défaut
    Citation Envoyé par BlaireauOne Voir le message
    liste.txt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    CLIENT1;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT2;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT3;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT4;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT5;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT6;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT7;NOM PRENOM;ADRESSE;CODE;VILLE
    interdit.txt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CLIENT2;
    CLIENT3;
    CLIENT6;
    Commande "join" :

    -v numéro
    Afficher sur la sortie standard, à la place du résultat habituel, une ligne pour chaque ligne du fichier numéro (1 ou 2), qui ne peut pas être appariée.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    join -t";" -v 1 liste.txt interdit.txt
    Résultat

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    CLIENT1;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT4;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT5;NOM PRENOM;ADRESSE;CODE;VILLE
    CLIENT7;NOM PRENOM;ADRESSE;CODE;VILLE
    intéressant le join je l'ai oublié, merci

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

Discussions similaires

  1. Une boucle pour supprimer des lignes ?
    Par eldoir dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 08/04/2012, 18h43
  2. Réponses: 3
    Dernier message: 25/12/2009, 09h29
  3. problème pour supprimer des lignes d'un fichier
    Par NicoO_O dans le forum Shell et commandes GNU
    Réponses: 5
    Dernier message: 17/01/2008, 07h23
  4. Réponses: 2
    Dernier message: 13/11/2007, 10h19
  5. Shell pour supprimer des lignes d'un fichier
    Par nelsa dans le forum Autres langages
    Réponses: 2
    Dernier message: 20/09/2004, 12h26

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