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 :

AWK - récupérer une seule fois des données qui apparaissent plusieurs fois


Sujet :

Shell et commandes GNU

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    68
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 68
    Points : 47
    Points
    47
    Par défaut AWK - récupérer une seule fois des données qui apparaissent plusieurs fois
    Bonjour,

    J'ai un fichier dans lequel est listé plusieurs user du type :

    root bidule
    toto trucmuche
    titi fdfsd
    root sdfdsf
    titi dfsdf
    tata dsfsdf
    tonton sdfsdf

    Ce qui m'intéresse c'est le premier champ (root, toto...) mias je voudrais les récupérer avec une seule occurence ou lieu des multiples.

    Au final je voudrais avoir le résultat suivant :

    root
    toto
    titi
    tata
    tonton

    j'ai trouvé cette commande là sur un site :

    awk '{if (x[$0] != "") next ; print $0 ; x[$0]=$0}'

    mais, si elle est bonne, je n'arrive pas à la comprendre et comment l'adapter.

    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 : 56
    Localisation : France

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

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

    uniq - Eliminer les lignes dupliquées dans un fichier trié.
    Ca ne conviendrait pas a ce que tu veux ? Associé avec sort et un pipe ?
    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 éclairé 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 : 60
    Localisation : France

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

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

    En reprenant les choses par le commencement, il faut:
    1) extraire le premier champ
    2) trier / éliminer les doublons

    Pour le 1), je vois deux possibilités: cut ou awk. Je préfère awk qui accepte les délimiteurs consécutifs (plusieurs blancs séparant deux champs sont considérés comme un seul). Pour le 2), je ne vois qu'une seule possibilité: sort -u qui trie (sort) puis élimine les doublons (option -u, comme la commande uniq). Cela donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cut -d ' ' -f 1 mon_fichier.txt | sort -u
    ou alors:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk '{print $1}' mon_fichier.txt | sort -u
    Mais la solution que tu proposes, même si elle ne fonctionne pas telle quelle (c'est pas $0, c'est $1), est astucieuse:
    la commande awk possède une propriété que Bash ignore: les tableaux associatifs dynamiques. En gros, au lieu d'avoir un tableau x[1]=val_1, x[2]=val_2..., on a: x[txt_1]=val_1, x[txt_2]=val_2... avec txt_i qui est du texte quelconque. En plus, il est possible d'ajouter des cases au tableau en cours d'exécution. Pour bien comprendre comment ça fonctionne, voici la décomposition de l'exécution de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    awk '
    {
        if (x[$1] != "")
        {
            next
        }
        print $1
        x[$1] = "1"
    } mon_fichier.txt
    sur les données suivantes (fichier mon_fichier.txt):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    root bidule
    toto trucmuche
    root machin
    
    Traitement de la ligne 1: "root bidule":
    $1 vaut "root" c'est-à-dire le premier champ de la ligne, x["root"] n'existe pas (le tableau x est encore vide), donc on n'entre pas dans le if. On imprime $1 (donc "root") puis on initialise x["root"] avec n'importe quoi (j'ai mis 1), donc x["root"] existe maintenant.

    Traitement de la ligne 2: "toto trucmuche":
    Idem que pour la ligne 1 avec $1 qui vaut maintenant "toto". "toto" est imprimé puis la case x["toto"] et créée et initialisée à 1 (on se fout de sa valeur, le principal est qu'il existe la case d'indice "toto" dans le tableau x).

    Traitement de la ligne 3: "root machin":
    Attention: $1 vaut à nouveau "root", comme à la première ligne! La case du tableau x["root"] existe déjà (elle vaut 1, mais p@#$%n on s'en fout!), donc cette fois-ci, on entre dans le if qui dit de passer à la ligne suivante.

    Voili voilou, j'espère que c'est clair. Merci pour l'astuce!
    Un problème bien posé est déjà résolu (H. Bergson).

  4. #4
    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 : 56
    Localisation : France

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

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

    Merci pour ces explications fort intéressantes jmelyn.

    Sinon ceci fonctionne tout aussi bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sort <ton_fichier> | cut -d " " -f 1 | uniq -u > ton_fichier_de_sortie
    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.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    68
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 68
    Points : 47
    Points
    47
    Par défaut
    Merci à tous les deux, et surtout à jmelyn pour le temps passer à expliquer la commande

    je ne connaissais pas le sort -u maintenant c'est fait

    bonne journée à vous

  6. #6
    Membre éclairé 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 : 60
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Points : 823
    Points
    823
    Par défaut Attention à la commande sort!
    Winnt,

    Attention, la solution que tu donnes est correcte dans le cas décrit mais pourrait ne pas fonctionner dans d'autres cas. Notamment lorsqu'il est nécessaire d'utiliser la commande join ensuite (join nécessite des fichiers parfaitement triés). La nuance est la suivante:

    La commande sort sans aucun paramètre fait le tri sur la ligne entière, donc le tri
    semble correct. Or, dans un dictionnaire, A se trouvera avant AA. Donc le tri n'est pas bon parce que généralement la variable LC_ALL ne vaut pas C, l'ordre du code ASCII n'est plus celui qu'on imagine. Pour corriger ça, il est bon de spécifier ce que l'on veut exactement, c'est-à-dire trier sur le premier champ uniquement.

    La commande sort -k 1,1 veut dire: trier du champ 1 au champ 1; sur le champ 1, quoi. Et là, ô miracle, ça marche
    Un problème bien posé est déjà résolu (H. Bergson).

  7. #7
    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 : 56
    Localisation : France

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

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

    Merci de cette précision jmelyn.

    Donc dans ce cas il convient de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cut -d " " -f 1 <ton_fichier> | sort | uniq -u > ton_fichier_de_sortie
    et non
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sort <ton_fichier> | cut -d " " -f 1 | uniq -u > ton_fichier_de_sortie
    J'ai droit à ma sucette ?
    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.

  8. #8
    Membre éclairé 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 : 60
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Points : 823
    Points
    823
    Par défaut
    Farpaitement! Dans le cas que tu présentes, il n'y a qu'un seul champ dans la ligne, donc le tri sera toujours correct. Bon, les deux commandes sort puis uniq peuvent être rassemblées en une seule: sort -u.

    Je ne saisis d'ailleurs pas bien la nuance entre uniq et uniq -u...
    Un problème bien posé est déjà résolu (H. Bergson).

  9. #9
    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 : 56
    Localisation : France

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

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

    Description
    Cette page de manuel documente la version GNU de uniq.

    uniq affiche les lignes uniques d'un fichier trié, ne conservant qu'un seul exemplaire de celles dupliquées.

    Il peut également ne montrer que les lignes n'apparaissant qu'une seule fois, ou celles apparaissant plusieurs fois.

    uniq réclame que le fichier d'entrée soit trié car il ne compare que les lignes consécutives.

    Si le fichier de sortie n'est pas mentionné, uniq écrit sur la sortie standard. Si le fichier d'entrée n'est pas précise non plus, uniq lit depuis l'entrée standard.
    Options

    -u, --unique
    N'afficher que les lignes uniques.
    -d, --repeated
    N'afficher que les lignes dupliquées.
    DESCRIPTION

    Cette page de manuel documente la version GNU de sort.

    sort trie, regroupe ou compare toutes les lignes des fichiers indiqués. Si aucun fichier n'est fourni, ou si le nom `-' est mentionné, la lecture se fera depuis l'entrée standard.

    Par défaut, sort écrit ses résultats sur la sortie standard.

    sort peut opérer suivant trois modes : tri (par défaut), regroupement, et vérification de l'ordre. Les options suivantes modifient le mode opératoire :

    -u Pour l'action par défaut, ou pour l'action -m, n'afficher que la première séquence de lignes considérées comme égales. Pour l'action -c, vérifier qu'aucune lignes consécutives ne soient égales.
    PS : J'ai donc dis une anerie il convient d'enlever le -u à la commande uniq
    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.

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

Discussions similaires

  1. Coller dans 1 seul fichier des données issues de plusieurs fichiers
    Par Lalou83 dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 19/09/2014, 08h42
  2. Réponses: 0
    Dernier message: 07/11/2013, 15h39
  3. [MySQL-5.1] type des données qui représente une liste
    Par gebtun dans le forum Requêtes
    Réponses: 3
    Dernier message: 04/04/2013, 09h37
  4. Comment récupérer des données qui se trouve dans un intranet
    Par mea4502 dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 05/02/2013, 13h58
  5. Réponses: 18
    Dernier message: 10/02/2005, 13h22

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