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 :

Calcul avec AWK


Sujet :

Shell et commandes GNU

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2020
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Avril 2020
    Messages : 6
    Par défaut Calcul avec AWK
    Bonjour à tous,

    J’essaie de faire un petit script qui évalue certains champs d'un CSV.
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    blablabla,blablabla,(47+(34/60)+(54.42/3600)),blablabla,blabla
    devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    blablabla,blablabla,47.58178333333333333332,blablabla,blabla

    J'ai un premier jet qui fonctionne pas trop mal :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    awk -F ',' 'function CALC( F ) {system ("echo \"" $F "\" | bc -l | tr -d \"\\n\"")} { for(i=1 ; i <= 13 ; i++) { printf "%s,",$i } ; CALC( 14 ); for(i=16 ; i <= NF ; i++) { printf "%s", ","$i }; print "\n"}' fichier.csv
    Mon problème est que cela est très,très long ....

    A priori avec printf, c'est bien plus rapide, mais impossible de le faire fonctionner...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    awk -F ',' 'function CALC( F ) {printf "%.3f\n", $F} { for(i=1 ; i <= 13 ; i++) { printf "%s,",$i } ;  CALC( 14 ); print "\n"}' fichier.csv
    Le $F contient bien ma chaine mais le retour = 0.000

    Voilà.

    Si l'un de vous a des idées, je suis preneur.

    Merci.

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 651
    Par défaut
    Bonjour,

    je pensais que strtonum aurait évalué la chaîne, mais non.
    alors j'ai fait un peu de stfw :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gawk 'BEGIN{FS=OFS=","}{"echo \""$3"\"| bc -l"|getline var; $3=var}1' tonFichier
    recourir au shell dans awk me rend chagrin.
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2020
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Avril 2020
    Messages : 6
    Par défaut
    Bonjour N_BaH,

    Merci pour ton retour. Ca fonctionne très bien et c'est bien plus jolie que ma première tentative ^^
    Cependant, le temps de traitement est toujours très long, enfin je suppose qu'il est "normal" avec un bc.

    J'ai donc une autre question, bc est-il le moyen le plus rapide de calculer des floats en shell ?
    Dans mon cas j'ai environ 2,5 millions d'enregistrement à traiter et j'aimerai être dans les 30min (la à priori entre 45min et 1H de traitement ).

    Merci.

  4. #4
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 347
    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 347
    Par défaut
    Une variante plus barbare toujours avec bc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    echo 'blablabla,blablabla,(47+(34/60)+(54.42/3600)),blabla,blabla' | awk -F ',' 'BEGIN{OFS=FS}"bc -l <<<\""$3"\"" | getline $16'
    blablabla,blablabla,(47+(34/60)+(54.42/3600)),blabla,blabla,,,,,,,,,,,47.58178333333333333332
    Et une version perl (peut-être plus rapide) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    echo 'blablabla,blablabla,(47+(34/60)+(54.42/3600)),blabla,blabla' | perl -F',' -ane '$,=",";chomp @F;print @F,",,,,,,,",(eval "$F[2]")."\n"'
    blablabla,blablabla,(47+(34/60)+(54.42/3600)),blabla,blabla,,,,,,,,,47.5817833333333

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 651
    Par défaut
    le shell ne sait pas calculer les nombres à virgule.
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  6. #6
    Membre émérite Avatar de balkany
    Homme Profil pro
    Touriste
    Inscrit en
    Juillet 2017
    Messages
    348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Touriste

    Informations forums :
    Inscription : Juillet 2017
    Messages : 348
    Par défaut
    Il me semble qu'il y a quand même plus performant, sans appeler l'évaluation à chaque ligne.
    Puisque le champ contenant les opérations est apparemment toujours à la même place :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    d=','; c=3; paste -d"$d" <(awk -F"$d" -vc=$c '{for(i=1;i<=c-2;i++) printf("%s"FS,$i); printf("%s\n",$i)}' f) <(bc -l < <(awk -F"$d" -vc=$c '{print $c}' f)) <(awk -F"$d" -vc=$c '{for(i=c+1;i<=NF-1;i++) printf("%s"FS,$i); printf("%s\n",$NF)}' f)
    Ce qui donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ cat f
    blablabla,blablabla,(47+(34/60)+(54.42/3600)),blablabla,blabla
    blablabla,blablabla,(47+(34/60)+(54.42/3600)),blablabla,blabla
    blablabla,blablabla,(47+(34/60)+(54.42/3600)),blablabla,blabla
    blablabla,blablabla,(47+(34/60)+(54.42/3600)),blablabla,blabla
    blablabla,blablabla,(47+(34/60)+(54.42/3600)),blablabla,blabla
    $ d=','; c=3; paste -d"$d" <(awk -F"$d" -vc=$c '{for(i=1;i<=c-2;i++) printf("%s"FS,$i); printf("%s\n",$i)}' f) <(bc -l < <(awk -F"$d" -vc=$c '{print $c}' f)) <(awk -F"$d" -vc=$c '{for(i=c+1;i<=NF-1;i++) printf("%s"FS,$i); printf("%s\n",$NF)}' f)
    blablabla,blablabla,47.58178333333333333332,blablabla,blabla
    blablabla,blablabla,47.58178333333333333332,blablabla,blabla
    blablabla,blablabla,47.58178333333333333332,blablabla,blabla
    blablabla,blablabla,47.58178333333333333332,blablabla,blabla
    blablabla,blablabla,47.58178333333333333332,blablabla,blabla
    $
    Si le champ contenant les opérations n'est pas toujours à la même place, il faut savoir comment le repérer, et mettre ça dans les différents awk : ça ne me semble pas poser de problème à priori.

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 651
    Par défaut
    sur 6M de lignes, la ligne de code, que j'ai trouvée en fouinant le net, est trois fois plus rapide.
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  8. #8
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 347
    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 347
    Par défaut
    Une version spéciale gawk:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gawk -F ',' 'BEGIN{OFS=FS}{print $3 |& "bc -l" ; "bc -l" |& getline $16}1' fichier
    Ici, gawk crée un sous process bc sur lequel il pipe l'entrée et la sortie, un seul process bc est lancé pour toute la lecture du fichier.

    Dans l'exemple présenté ici, on envoi sur l'entrée et on récupère tout de suite la sorti de bc, mais rien n'empêche de faire d'autres actions entre les deux.

  9. #9
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 102
    Par défaut
    Citation Envoyé par mercosivo Voir le message
    J’essaie de faire un petit script qui évalue certains champs d'un CSV.
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    blablabla,blablabla,(47+(34/60)+(54.42/3600)),blablabla,blabla
    devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    blablabla,blablabla,47.58178333333333333332,blablabla,blabla
    Quand je vois ça, ça me fait penser à quelqu'un qui essaierait de transformer "47 heures, 34 minutes et 54.42 secondes" en "47.58178333333333333332 heures".

    Je ne sais pas s'il existe des fonctions plus rapides que les 2 divisions et les sommes...

    J'ai aussi un peu de mal à imaginer dans quel contexte il serait véritablement et sensément indispensable d'avoir ce format pour le moins non conventionnel.

    Bref, si c'était mon projet, je changerais le process qui génère le fichier pour:
    - soit lui faire mettre dans 3 champs séparés les heures, minutes et secondes
    - soit lui faire faire lui-même le calcul et mettre le résultat dans le champ!

    Évidemment, comme d'habitude, j'imagine qu'il est fort probable que le changement de format du fichier ne soit pas une option envisageable...

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

Discussions similaires

  1. Réponses: 17
    Dernier message: 28/07/2017, 23h08
  2. Réponses: 7
    Dernier message: 17/02/2012, 11h57
  3. Réponses: 33
    Dernier message: 15/10/2004, 16h19
  4. Problème sur une cmd avec AWK
    Par OrangeBud dans le forum Linux
    Réponses: 3
    Dernier message: 02/06/2004, 10h51
  5. Réponses: 2
    Dernier message: 22/03/2004, 10h50

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