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] - Parser un fichier texte avec awk


Sujet :

Shell et commandes GNU

  1. #1
    Candidat au Club
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Août 2015
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Août 2015
    Messages : 7
    Points : 4
    Points
    4
    Par défaut [AWK] - Parser un fichier texte avec awk
    Bonjour à tous,


    J'ai un petit problème avec AWK. J'ai un gros fichier texte (récupéré depuis une APIREST) que j'ai besoin de parser et réécrire quelques éléments. Je m'étais orienté vers une boucle qui lit toutes les lignes du fichier (while / read) mais c'est beaucoup trop long.
    Je me suis dit que la meilleur manière de faire, la plus optimisé, est d'utiliser awk. Mais je me heurte à un problème...

    Voici le contenu de mon fichier :
    ...
    FRA118;FR240;20180714;20180714;holiday
    FRA118;FR240;20181111;20181111;holiday
    FRA118;FR240;20181202;20181202;exceptional
    ...

    L'idée c'est, sur chaque ligne, prendre la première date (en $3) et de la réécrire avec juste le jour. Par exemple, pour "20180714", je veux "mardi" à la place.

    voilà ou j'en suis :
    Sur une ligne ça marche avec ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    echo "FRA118;FR240;20180714;20180714;holiday" | awk -F";" 'BEGIN {OFS="/"} {cmd = "date -d \"" $3 "\" \"+%A\"" |& getline d;close(cmd);print $1 ";" $2 ";" d ";" substr($4,7,2), substr($4,5,2), substr($4,1,4) ";" $5}'
    mais lorsque je spécifie le fichier... :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk -F";" 'BEGIN {OFS="/"} {cmd = "date -d \"" $3 "\" \"+%A\"" |& getline d;close(cmd);print $1 ";" $2 ";" d ";" substr($4,7,2), substr($4,5,2), substr($4,1,4) ";" $5}' TOTO2.txt
    J'avais aussi cette alternative mais ça ne marche pas non plus, j'ai tout le temps le même jour... :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk -F";" 'BEGIN {OFS="/"} {s=strftime("%A", ($3), 1) ;print $1 ";" $2 ";" (s) ";" substr($4,7,2), substr($4,5,2), substr($4,1,4) ";" $5}' TOTO2.txt
    C'est fou car sur les premières lignes de mon fichier, j'ai bien le résultat attendu mais à un moment donné, ça ne marche plus et awk me renvoie des mauvais jours et sur 40 lignes parfois... Ça je ne comprend pas...

    Je vous met en PJ le fichier texte que je veux traiter.

    Si quelqu'un a une idée ou une autre manière de faire sans être obligé de lire le fichier ligne par ligne, je suis preneur
    Merci de votre aide !

    TOTO2.txt

    Cordialement,
    Johann

  2. #2
    Expert éminent sénior Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 243
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 243
    Points : 13 458
    Points
    13 458
    Par défaut
    Bonjour

    Tu fais tout en même temps.
    Prends ton temps.
    Ce n'est pas cmd="blabla" | getline d;close(cmd);.
    Mais cmd="blabla"; cmd | getline d;close(cmd);.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ tail TOTO2.txt
    FRA079;FR240;20180510;20180510;holiday
    FRA079;FR240;20180402;20180402;holiday
    FRA058;FR240;20180714;20180714;holiday
    FRA058;FR240;20181111;20181111;holiday
    FRA058;FR240;20181223;20181223;exceptional
    FRA058;FR240;20181225;20181225;holiday
    FRA058;FR240;20180101;20180101;holiday
    FRA058;FR240;20180501;20180501;holiday
    FRA058;FR240;20180521;20180521;holiday
    FRA058;FR240;20181209;20181209;exceptional

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ awk -F";" 'BEGIN {OFS="/"} {cmd = "date -d \"" $3 "\" \"+%A\"";cmd | getline d;close(cmd);print $1 ";" $2 ";" d ";" substr($4,7,2), substr($4,5,2), substr($4,1,4) ";" $5}' TOTO2.txt |tail
    FRA079;FR240;jeudi;10/05/2018;holiday
    FRA079;FR240;lundi;02/04/2018;holiday
    FRA058;FR240;samedi;14/07/2018;holiday
    FRA058;FR240;dimanche;11/11/2018;holiday
    FRA058;FR240;dimanche;23/12/2018;exceptional
    FRA058;FR240;mardi;25/12/2018;holiday
    FRA058;FR240;lundi;01/01/2018;holiday
    FRA058;FR240;mardi;01/05/2018;holiday
    FRA058;FR240;lundi;21/05/2018;holiday
    FRA058;FR240;dimanche;09/12/2018;exceptional

    • Bravo de penser au close(cmd).
    • A ta place, je morcellerais année, mois et jour par des points-virgules pour se débarrasser définitivement du problème de parsing.


    Bonne suite
    Cette réponse vous apporte quelque chose ? Cliquez sur en bas à droite du message.

  3. #3
    Candidat au Club
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Août 2015
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Août 2015
    Messages : 7
    Points : 4
    Points
    4
    Par défaut
    Merci pour ta réponse et ta réactivité Je me suis pourtant arraché les cheveux dessus

    Par curiosité, sais-tu si la commande avec strtime (commande interne à awk) est plus optimisé/adapté pour faire ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk -F";" 'BEGIN {OFS="/"} {s=strftime("%A", ($3), 1) ;print $1 ";" $2 ";" (s) ";" substr($4,7,2), substr($4,5,2), substr($4,1,4) ";" $5}' TOTO2.txt
    Merci

  4. #4
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 278
    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 278
    Points : 12 726
    Points
    12 726
    Par défaut
    Bonjour,
    Tu n'as qu'a le vérifier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk -F\; 'BEGIN{OFS=FS}{$3=strftime("%A", mktime(gensub(/(....)(..)(..)/,"\\1 \\2 \\3 00 00 00","g",$4)), 0);$4=strftime("%d/%m/%Y", mktime(gensub(/(....)(..)(..)/,"\\1 \\2 \\3 00 00 00","g",$4)), 0)}1' fichier
    Cordialement.

  5. #5
    Candidat au Club
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Août 2015
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Août 2015
    Messages : 7
    Points : 4
    Points
    4
    Par défaut
    Hello,


    je confirme ! la commande en passant par les commandes interne à AWK est quand même bien plus rapide !

    Est-ce que tu peux m'expliquer brièvement ta commande notamment sur mktime et gensub ?

    Merci encore pour votre aide,
    Johann

  6. #6
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Ta deuxième version ne marche pas car le deuxième paramètre de strftime doit être au format temps UNIX (secondes depuis le 1/1/1970), tu peux l'obtenir grâce à mktime en lui passant un format YYYY MM DD hh mm ss:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #!/usr/bin/awk -f
     
    BEGIN {
        dtpat="^....|..\\B"
        OFS=FS=";"
    }
    {
        gsub(dtpat, "& ", $3)
        gsub(dtpat, "& ", $4)
     
        $3=strftime("%A", mktime($3" 0 0 0"))
        $4=strftime("%d/%m/%Y", mktime($4" 0 0 0"))
    }1
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  7. #7
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 278
    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 278
    Points : 12 726
    Points
    12 726
    Par défaut
    Je ne suis pas étonné que ça soit plus rapide, ici on utilise une lib alors que la version avec date crée un processus pour chaque appelle à la commande qui soi-dit en passant, appelle certainement la même lib.

    Pour les explications, dans le man de gawk:
    Fonctions de Temps

    Puisqu'une des utilisations principales des programmes AWK est le traitement de fichiers journaux qui contiennent des informations d'horodate, gawk fournit les deux fonctions suivantes pour l'obtention des horodates et leur formatage.

    mktime(spéc-date)
    Convertit spéc-date en une horodate de la même forme que celle retournée par systime(). La spéc-date est une chaîne de la forme AAAA MM JJ HH MM SS[ DST] (Daylight Saving Time). Le contenu de la chaîne est constitué de six ou sept nombres représentant respectivement l'année complète en incluant le siècle, le mois entre 1 et 12, le jour du mois entre 1 et 31, l'heure de la journée entre 0 et 23, la minute entre 0 et 59, la seconde entre 0 et 59, et un drapeau optionnel « daylight saving » (changement horaire lors du passage à l'heure d'été).

    Les valeurs de ces nombres ne doivent pas forcément se situer dans les intervalles spécifiés ; par exemple, une heure de -1 signifie 1 heure avant minuit. Le calendrier grégorien avec origine zéro est implicitement utilisé, avec l'année 0 précédant l'année 1, et l'année -1 précédant l'année 0. L'heure est supposé être exprimée dans le fuseau horaire local. Si le drapeau de changement horaire est positif, l'heure est supposée être l'heure d'été ; s'il est nul, l'heure est supposée être l'heure standard ; et, s'il est négatif (le défaut), mktime() essaiera de déterminer si l'heure d'été a cours pour l'heure spécifiée. Si spéc-date ne contient pas assez d'éléments ou si l'heure résultante est hors borne, mktime() renvoie -1.
    strftime([format [, horodate]])
    Formate l'horodate en fonction de la spécification de format. L'horodate devrait être de la même forme que celle renvoyée par systime(). Si horodate manque, l'heure du jour courante est utilisée. Si format n'est pas présent, un format par défaut équivalent à la sortie de date(1) est utilisé. Voyez la spécification de la fonction strftime() du C ANSI pour savoir quelles conversions de format sont garanties être disponibles. Une version du domaine public de strftime(3) et la page de manuel qui l'accompagne sont livrées avec gawk ; si cette version a été utilisée pour construire gawk, alors toutes les conversions décrites dans cette page de manuel sont disponibles pour gawk.
    systime()
    Renvoie l'heure actuelle sous forme du nombre de secondes écoulées depuis le début de l'Epoch (le 1er Janvier 1970 à minuit GMT sur les systèmes POSIX).
    Si on résume:
    -mktime() convertie une date au format "AAAA MM JJ HH MM SS[ DST]" en une horodate du même format retourné par systime().
    -strftime() formate une horodate de format systime() (et donc mktime() ) en fonction de la spécification du format.

    Et le gensub(), n'est là que pour transformer ta chaine AAAAMMJJ en AAAA MM JJ 00 00 00 qui est le format reconnu par mktime.

    D'ailleurs, pour le champs 4 ($4), pas besoin de strftime et mktime, un $4=gensub(/(....)(..)(..)/,"\\3/\\2/\\1","g",$4) serait suffisant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk -F\; 'BEGIN{OFS=FS}{$3=strftime("%A", mktime(gensub(/(....)(..)(..)/,"\\1 \\2 \\3 00 00 00","g",$3)), 0);$4=gensub(/(....)(..)(..)/,"\\3/\\2/\\1","g",$4)}1' fichier
    PS: Ce qui me fait remarqué une typo dans le awk de mon post précédent (je modifie le champs 3 avec la donnée du champs 4)
    Cordialement.

Discussions similaires

  1. Fichier output avec awk
    Par nina2007 dans le forum Shell et commandes GNU
    Réponses: 3
    Dernier message: 09/02/2015, 11h41
  2. analyser fichier trace avec awk
    Par pfe_smile dans le forum Linux
    Réponses: 2
    Dernier message: 30/08/2012, 23h16
  3. concaténer plusieurs fichiers xml avec awk
    Par flora806 dans le forum Linux
    Réponses: 0
    Dernier message: 19/06/2009, 17h18
  4. pb formatage d'un fichier txt avec awk ou SHELL en géneral
    Par ammah dans le forum Applications et environnements graphiques
    Réponses: 1
    Dernier message: 26/09/2008, 15h25
  5. Réponses: 5
    Dernier message: 09/01/2005, 19h54

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