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 :

Recherche dans un fichier et récursivité


Sujet :

Shell et commandes GNU

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2009
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 80
    Par défaut Recherche dans un fichier et récursivité
    Bonjour,

    J'ai un fichier csv en entrée qui se présente comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    col1;col2
    CC;ZZ
    ZZ;BB
    BB;SS
    EE;QQ
    GG;WW
    WW;ZZ
    Je souhaite avoir en sortie ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    col1;col2
    CC;SS
    EE;QQ
    GG;ZZ
    Je m'explique pour le premier résultat attendu. Les autres suivent le même raisonnement :
    - je lis la première ligne et je note la valeur de la col1, ici CC
    - toujours sur cette ligne, je prends le contenu de col2, ici ZZ
    - je recherche la chaîne ZZ dans la suite du fichier et sur la première colonne
    - je la trouve, le prends la valeur de la col2, ici BB
    - je recherche la chaîne BB dans la suite du fichier et sur la première colonne
    - je la trouve, le prends la valeur de la col2, ici SS
    - je recherche la chaîne SS dans la suite du fichier et sur la première colonne
    - je ne la trouve pas, j'affiche la valeur de col1 lue au tout début et la valeur de col2 de la dernière trouvaille, ici CC;SS

    J'ai déjà posé cette question sur le forum SQL et j'ai eu une réponse mais comme j'ai aussi la possibilité d'utiliser le shell, je fais appel à votre expertise en shell/Awk/Sed.

    Merci pour votre aide.

  2. #2
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut
    Salut,

    perso je créerai une liste indexée de type colone1 => colone2 en lisant ligne par ligne le fichier.

    Il faudrait créer une fonction récursive qui recherche la valeur dans la liste.

    si dans la fonction, on trouve une clé on relance la fonction avec la valeur sinon on affiche la valeur.

  3. #3
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 293
    Par défaut
    Bonjour

    L'exemple que tu as cité est-il faux ? Voilà ce que je trouve :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ awk -F';' '(NR==1){next;} {s[$1]=$2;p[$2]=1;} END{OFS=FS;for (i in s) if (p[i]!=1) {c=i;while (s[c]!="") c=s[c];print i,c} }' fichier.txt
    CC;SS
    EE;QQ
    GG;SS
    • On voit que la différence est dans le traitement de GG. Une fois que GG renvoie vers ZZ, faut-il se souvenir que ZZ renvoie vers BB ? Ou non ?
    • Ce code au déboté n'a pas de protection contre les références circulaires.

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 664
    Par défaut
    il me semble vous avoir déjà vu plus dur avec des personnes qui posent des questions qui attendent qu'on fasse le boulot sans un début de solution.
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  5. #5
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 358
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 358
    Par défaut
    moi, j'ai l'impression que ça lecture est linéaire d'après l'exemple qu'il donne.

    En gros, la valeur de la col2 doit-être la valeur de la col1 de la ligne juste après, ou alors, son exemple d'ensemble de départ est un cas particulier

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2009
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 80
    Par défaut
    @Flodelarab : excellente remarque. C'est tout à fait ça. Je me suis mélangé les pinceaux avec le ZZ.
    Je reprends donc pour éclairer les admirateurs du site :

    En entrée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    col1;col2
    CC;ZZ
    ZZ;BB
    BB;SS
    EE;QQ
    GG;WW
    WW;JJ
    En sortie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    col1;col2
    CC;SS
    ZZ;XX
    EE;QQ
    GG;JJ
    @disedorgue : non ce n'est pas linéaire. Il est possible d'avoir :
    En entrée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    col1;col2
    CC;ZZ
    AA;BB
    KK;SS
    ZZ;QQ
    BB;MM
    En sortie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    col1;col2
    CC;QQ
    AA;MM
    KK;SS
    J'ai une relation de petit-fils , fils et père.
    En gros, dans cet exemple, CC = petit fils, ZZ=fils et QQ=père. Je tente donc de relier le petit fils CC à son grand-père QQ en zappant le père.

  7. #7
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 358
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 358
    Par défaut
    Ok, peut-on aussi dire que:
    -une ligne ne doit être prise en compte qu'une et une seule fois
    -Il n'y a pas de doublon en col2
    -il n'y a pas de doublon en col1

  8. #8
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 293
    Par défaut
    Le nouvel exemple ne correspond toujours pas. Pourquoi ZZ est en sortie, et pas BB par exemple ?

    Je corrige juste une chose sans rapport :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $ awk -F';' '(NR==1){print;next;} {s[$1]=$2;p[$2]=1;} END{OFS=FS;for (i in s) if (p[i]!=1) {c=i;while (s[c]!="") c=s[c];print i,c} }' fichier.txt 
    col1;col2
    CC;SS
    EE;QQ
    GG;JJ
    @N_BaH : C'est juste un indice. M'étonnerait que cela suffise.

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2009
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 80
    Par défaut
    Merci beaucoup. ça répond à mon besoin.
    Je vais quand même devoir m'y mettre pour essayer de comprendre le code. En attendant, une ch'tite explication ne serait pas de refus.

    Merci encore, vous êtes des pros !

  10. #10
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 293
    Par défaut
    awk Étudions le fichier ligne à ligne
    -F';' le séparateur de champs est le point-virgule.

    (NR==1){} Pour la première ligne, on ...
    {} Pour toutes les lignes, on ...
    END{} Après avoir lu toutes les lignes, on ...

    s : tableau associatif des Suivants
    p : tableau associatif des Pas-affichés.
    s[$1]=$2; Le suivant du premier champ est le deuxième champ.
    p[$2]=1; Un champ atteint de l'entrée ne peut être un premier champ de la sortie. Marqueur.

    OFS=FS; Le séparateur de champ de sortie est le même que le séparateur de champ d'entrée (ici, le point-virgule)

    Le reste c'est classique. Pas exclusivement du shell.

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 664
    Par défaut
    Je vais quand même devoir m'y mettre
    il serait temps!
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  12. #12
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut
    Salut, une version fullbash

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    # Pour l'exemple
    echo 'CC;ZZ
    ZZ;BB
    BB;SS
    EE;QQ
    GG;WW
    WW;JJ' > Fichier.txt
    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
    # Fonction s'appelant elle-même si besoin
    caca()
    {
        # Si on retrouve la valeur dans les clés de la liste, on relance la fonction avec la valeur de cette clé
        if [[ "${!SuperVar[@]}" =~ "${1}" ]]
        then
            caca "${SuperVar[$1]}"
     
        # Sinon, on affiche simplement la valeur
        else
            echo "${1}"
        fi
    }
     
    # Déclaration du tableau associatif qui évite de rechercher dans le fichier à chaque fois
    declare -A SuperVar
     
    # Lecture du fichier ligne par ligne pour remplir le tableau
    while read Line
    do
        # Attribution clé = valeur
        SuperVar[${Line%;*}]=${Line#*;}
    done < Fichier.txt
     
    # Pour chaque clé du tableau, rangée
    for Cle in "${!SuperVar[@]}"
    do
        # Récupération de la valeur associée
        Valeur=${SuperVar[${Cle}]}
     
        # Affichage de la clé et de sa valeur finale
        [[ ! "${SuperVar[@]}" =~ "${Cle}" ]] && echo "${Cle} : $(caca ${Valeur})"
    done | sort
    ce qui donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CC : SS
    EE : QQ
    GG : JJ

  13. #13
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 358
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 358
    Par défaut
    Non, pas fullbash, le sort final n'est pas bash (mais c'est beau quand même)

  14. #14
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 293
    Par défaut
    Très bien.

    Tu récupères la ligne pour la parser à la main. Mais tu pourrais confier ce travail à "read".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    while IFS=';' read clef valeur reste
    do
        # Attribution clé = valeur
        SuperVar[$clef]=$valeur
    done < Fichier.txt

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

Discussions similaires

  1. Améliorer la recherche dans un fichier?
    Par abdmaa dans le forum Algorithmes et structures de données
    Réponses: 4
    Dernier message: 09/05/2005, 13h09
  2. [LG]Runtime Error lors d'une recherche dans un fichier
    Par Fraynor dans le forum Langage
    Réponses: 2
    Dernier message: 15/03/2005, 22h51
  3. Rechercher dans un fichier avec emacs
    Par ggnore dans le forum Applications et environnements graphiques
    Réponses: 2
    Dernier message: 24/11/2004, 10h28
  4. recherche dans un fichier xml (castor)
    Par pingoui dans le forum Format d'échange (XML, JSON...)
    Réponses: 8
    Dernier message: 06/09/2004, 14h28
  5. [LG]rechercher dans un fichier texte
    Par BadFox dans le forum Langage
    Réponses: 11
    Dernier message: 01/12/2003, 15h57

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