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 :

[Shell] Enrichissement de fichier


Sujet :

Linux

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut [Shell] Enrichissement de fichier
    Bonjour,

    Je bute sur un problème qui me semblait fort simple et qui pour moi ne l'est pas fianlement

    J'ai donc 2 fichiers :
    A et B

    A est composé de x Lignes de 2 champs de 11 carctères separes par une virgule
    B est un fichier quelconque

    Je voudrais rechercher dans B le premier champ de A, et si je le trouve ajouter à la fin de la ligne correspondante dans B le second champ de A, ceci jusqu'à la fin du parcours de B.

    Pourriez vous m'aider svp ?
    Merci d'avance.

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par MarcCC Voir le message
    Bonjour,

    Je bute sur un problème qui me semblait fort simple et qui pour moi ne l'est pas fianlement

    J'ai donc 2 fichiers :
    A et B

    A est composé de x Lignes de 2 champs de 11 carctères separes par une virgule
    B est un fichier quelconque

    Je voudrais rechercher dans B le premier champ de A, et si je le trouve ajouter à la fin de la ligne correspondante dans B le second champ de A, ceci jusqu'à la fin du parcours de B.

    Pourriez vous m'aider svp ?
    Merci d'avance.
    Pas de problème. Un parcours de B où, pour chaque ligne, on va voir si l'info de "A" y est. Si la ligne contient l'info on y rajoute le champ de A. Et on écrit le tout dans C parce qu'on ne peut pas facilement à la fois lire et écrire
    Un peu long car tu feras A x B itérations mais simple à écrire en shell (mais moi je conseillerais le Python)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #!/bin/bash
    # Création d'un flux contenant le fichier à lire et d'un flux redirigé fers le fichier à écrire
    exec 3<fichierB
    exec 5>fichierC
     
    # Lecture de B
    while read ligneB 0<&3
    do
        # Petit affichage de contrôle (facultatif mais ça montrera la progression)
        echo "$ligneB"
     
        # Création d'un flux contenant le fichier à lire
        exec 4<fichierA
        # Lecture de A
        while read ligneA 0<&4
        do
            # Extraction champ 1 de la ligne A
            c1=`echo $ligneA |cut -f1 -d,`
     
            # Si le champ 1 est dans la ligne B
            if echo $ligneB |grep "$c1" 1>/dev/null
            then
                 # On y rajoute le champ 2 de la ligne A
                 ligneB="$ligneB `echo $ligneA |cut -f2 -d,`"
            fi
        done
     
        # On écrit la ligne finale dans C
        echo "$ligneB" 1>&5
    done
    Si les deux fichiers ne sont pas trop gros ça devrait aller. Sinon faut l'écrire en Python (1000 fois plus rapide). Je le ferais bien ici mais j'ai pas trop le temps. Si personne ne l'a fait à mon retour je reprendrai ce post...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    Merci pour cette réponse ultra rapide

    J'ai essayé mais en ksh, le bash n'est pas dispo, mais il me sort l'erreur suivante :

    ./TEST.ksh[2]: 3: not found.

    Par rapport au script la seule chose qui change c'est celà :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    #!/bin/ksh
    exec 3 </DVCC_data/VS/prm/TEMP-B
    exec 4 </DVCC_data/VS/prm/TEMP-A
    exec 5 >/DVCC_data/VS/prm/TEMP-C
    Autre question, celà ser à quoi "0"
    dans
    Par contre j'ai essayé cà et ca tourne en boucle mais ca passe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    #!/bin/ksh
     
    # Lecture de ACCAD
    while read ligneB 
    do
        # Petit affichage de contrôle (facultatif mais ça montrera la progression)
        echo "$ligneB"
     
        # Lecture de A
        while read ligneA 
        do
            echo "$ligneA"
            # Extraction champ 1 de la ligne A
            c1=`echo $ligneA |cut -f1 -d,`
     
            # Si le champ 1 est dans la ligne B
            if echo $ligneB |grep "$c1" 1>/dev/null
            then
                 # On y rajoute le champ 2 de la ligne A
                 ligneB="$ligneB `echo $ligneA |cut -f2 -d,`"
            fi
        done <TEMP-A
     
        # On écrit la ligne finale dans C
        echo "$ligneB" 1>-C
    done <TEMP-B

    Par contre python n'est pas dispo, perl oui.

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par MarcCC Voir le message
    Merci pour cette réponse ultra rapide

    J'ai essayé mais en ksh, le bash n'est pas dispo, mais il me sort l'erreur suivante :

    ./TEST.ksh[2]: 3: not found.
    Erreur de ma part, faut pas d'espace entre "3" et "<" (j'ai rectifié mon code). Mais si ça ne marche toujours pas alors passe le script en "/bin/sh" et là ça marchera...

    Citation Envoyé par MarcCC Voir le message
    Autre question, celà ser à quoi "0"
    dans
    Tu rediriges l'entrée standard (le clavier) sur le contenu du flux n° 3 (le fichier B) donc l'info stockée dans "ligneB" sera prise à partir du flux 3 (le fichier) et celui-ci sera automatiquement vidé de ce qui a été lu. Donc "0" représente "le clavier". Inutile dans 95% des cas sauf quand il faut dire "quoi sera pris à partir d'un autre flux" (un peu comme "." est inutile dans 95% des cas sauf quand il faut explicitement nommer le répertoire local)

    Oups !!! En écrivant que le flux était automatiquement vidé, ça me fait penser que le flux 4 a aussi été vidé lors du traitement de la première ligne. Donc pour que ça marche complètement faut que tu décales le "exec 4<fichierA" sous le "do" du premier while (avant le "read ligneA"). J'ai aussi rectifié mon post...

    Citation Envoyé par MarcCC Voir le message
    Par contre j'ai essayé cà et ca tourne en boucle mais ca passe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #!/bin/ksh
     
    # Lecture de ACCAD
    while read ligneB 
    do
        # Petit affichage de contrôle (facultatif mais ça montrera la progression)
        echo "$ligneB"
     
        # Lecture de A
        while read ligneA 
        do
            echo "$ligneA"
            # Extraction champ 1 de la ligne A
            c1=`echo $ligneA |cut -f1 -d,`
     
            # Si le champ 1 est dans la ligne B
            if echo $ligneB |grep "$c1" 1>/dev/null
            then
                 # On y rajoute le champ 2 de la ligne A
                 ligneB="$ligneB `echo $ligneA |cut -f2 -d,`"
            fi
        done <TEMP-A
     
        # On écrit la ligne finale dans C
        echo "$ligneB" 1>-C
    done <TEMP-B
    Bizarre que ça tourne en boucle !!! Car c'est aussi comme ça que j'aurais pu l'écrire sauf que je préfère utiliser les flux numérotés plutôt que les "< fic" mais c'est aussi une solution correcte...

    Citation Envoyé par MarcCC Voir le message
    Par contre python n'est pas dispo, perl oui.
    Désolé, je ne sais pas programmer en perl. Lorsque j'ai voulu apprendre un de ces deux langages j'ai choisi Python car plus récent...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    Ok merci celà fonctionne
    Par contre celà est très très long

    Le fichier A contient 11738 ligne et le B contient 488, soit en tout plus de 5 millions de passage

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par MarcCC Voir le message
    Le fichier A contient 11738 ligne et le B contient 488, soit en tout plus de 5 millions de passage
    Hé oui. C'est un peu le problème. T'aurais eu le contraire (à savoir A petit) t'aurais pu le stocker dans un tableau mais là, t'es coincé ou alors tu converti le programme en perl ou en C.

    Tu peux un peu optimiser le truc en introduisant un break intelligent si l'info de A est trouvée (ce qui signifie que tu ne cherches qu'une seule info parce que moi j'ai fait comme si la ligne de B pouvait contenir plusieurs infos de A) mais ce sera faible comme optimisation.
    T'as aucun moyen d'avoir Python ???
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    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
    Solution avec awk :
    http://www.shellunix.com/awk.html
    http://lea-linux.org/cached/index/Dev-awk.html


    FicA
    ====
    11,AA
    22,BB
    33,CC
    44,DD

    FicB
    ====
    exemple de ligne quelconque avec 33
    exemple de ligne quelconque avec 22
    exemple de ligne quelconque sans correspondance
    exemple de ligne quelconque avec 44
    exemple de ligne quelconque avec 11 44 22

    Traitement :
    5 EnregB chargés en mémoire
    Fin Traitement

    result.txt
    ==========
    exemple de ligne quelconque avec 33 CC
    exemple de ligne quelconque avec 22 BB
    exemple de ligne quelconque sans correspondance
    exemple de ligne quelconque avec 44 DD
    exemple de ligne quelconque avec 11 44 22 AA BB DD
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    echo -e "\nFicA\n===="
    cat FicA
    echo -e "\nFicB\n===="
    cat FicB
     
    echo -e "\nTraitement : "
    awk -F"," -v FicB=FicB '
    BEGIN {
    	#
    	### Chargement des enregs. de  FicB en mémoire
    	#
    	iMax=1
    	while (getline EnregB[iMax] < FicB > 0) {
    		iMax++
    	}
    	iMax--
    	print iMax" EnregB chargés en mémoire" | "cat 1>&2"
    }
    {
    	#
    	### pour chaque enreg de FicA, recherche si correspondance dans FicB 
    	### Mise à jour du ou des enregB si "matching".
    	#
    	for (i=1 ; i <= iMax ; i++) {
    		if (match(EnregB[i],$1)) {
    			EnregB[i]=EnregB[i]" "$2
    		}
    	}
    }
    END {
    	for (i=1 ; i <= iMax ; i++) {
    		print EnregB[i]
    	}
    } ' FicA > result.txt
     
    echo -e "Fin Traitement\n"
    echo -e "result.txt\n=========="
    cat result.txt
    Loi de Murphy:
    La Théorie c'est quand ça ne marche pas mais que l'on sait pourquoi.
    La Pratique c'est quand ça marche mais qu'on ne sait pas pourquoi.
    Quand la théorie rejoint la pratique ça ne marche pas et on ne sait pas pourquoi.

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    Celà peut être tentant comme méthode, il faudra que j'essaye Lundi

    Sinon, on peut aussi fabriquer des fichiers triers et le traiter par appariement non ?

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par BlaireauOne Voir le message
    Solution avec awk :
    http://www.shellunix.com/awk.html
    http://lea-linux.org/cached/index/Dev-awk.html




    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    echo -e "\nFicA\n===="
    cat FicA
    echo -e "\nFicB\n===="
    cat FicB
     
    echo -e "\nTraitement : "
    awk -F"," -v FicB=FicB '
    BEGIN {
    	#
    	### Chargement des enregs. de  FicB en mémoire
    	#
    	iMax=1
    	while (getline EnregB[iMax] < FicB > 0) {
    		iMax++
    	}
    	iMax--
    	print iMax" EnregB chargés en mémoire" | "cat 1>&2"
    }
    {
    	#
    	### pour chaque enreg de FicA, recherche si correspondance dans FicB 
    	### Mise à jour du ou des enregB si "matching".
    	#
    	for (i=1 ; i <= iMax ; i++) {
    		if (match(EnregB[i],$1)) {
    			EnregB[i]=EnregB[i]" "$2
    		}
    	}
    }
    END {
    	for (i=1 ; i <= iMax ; i++) {
    		print EnregB[i]
    	}
    } ' FicA > result.txt
     
    echo -e "Fin Traitement\n"
    echo -e "result.txt\n=========="
    cat result.txt
    Héhé... t'es trop fort en awk. J'y avais pensé aussi mais j'ai pas le niveau


    Citation Envoyé par MarcCC Voir le message
    Sinon, on peut aussi fabriquer des fichiers triers et le traiter par appariement non ?
    Ben le problème tel que tu l'as posé à l'origine est de chercher l'info de A n'importe où dans la ligne de B. Donc trier B je veux bien mais sur quel critère (et surtout on ne sait pas si l'ordre initial n'a pas une importance). Et trier A je veux bien mais à quoi ça servirait ???
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  10. #10
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    Le fichier A contient 2 Champs, le premier champ est le critere de recherche dans le fichier B.

    Si tu trie A sur le 1er champ (colonne 1 à 11) et B colonne 6 à16, tu peut alors faire une recherche par appariement. En gros c un parcours de A et B simultanement tout en recherchant les cles dans A et B.

  11. #11
    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
    Sauf erreur de ma part, tu n'avais pas précisé que le champ à chercher dans le fichier B était en colonne 6 à 16.
    Afin de t'aider plus efficacement, il serait souhaitable que nous ayons tous les éléments du problème.
    Aussi, je te suggère de poster un extrait de tes fichiers A et B
    Loi de Murphy:
    La Théorie c'est quand ça ne marche pas mais que l'on sait pourquoi.
    La Pratique c'est quand ça marche mais qu'on ne sait pas pourquoi.
    Quand la théorie rejoint la pratique ça ne marche pas et on ne sait pas pourquoi.

  12. #12
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    Ok, je vous en fournirait un Lundi.

Discussions similaires

  1. [système]shell + Nom de fichier avec Espace
    Par delphine_lep dans le forum Access
    Réponses: 3
    Dernier message: 23/03/2007, 16h24
  2. shell unix charger fichiers de variables
    Par waloo16 dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 31/01/2007, 17h29
  3. Réponses: 2
    Dernier message: 25/09/2006, 18h46
  4. Shell - Merge de fichiers
    Par tesla dans le forum Linux
    Réponses: 4
    Dernier message: 29/06/2004, 02h10
  5. Commande en shell -- Sur les fichiers
    Par OrangeBud dans le forum Linux
    Réponses: 8
    Dernier message: 18/05/2004, 13h13

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