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 :

bash, awk etc


Sujet :

Shell et commandes GNU

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 4
    Points : 2
    Points
    2
    Par défaut bash, awk etc
    bonjour,
    j'ai un fichier comme celui ci (date en annee/mois/jour - valeur):
    ...
    20001212 5
    20001228 5
    20001229 4.3
    20001230 25.2
    20001231 32
    etc ....

    je cherche une commande en bash, pour que si une date est manquante dans mon fichier
    (ici par exemple entre 20001212 et 20001228, il manque des jours) ,
    alors il faut ajouter les dates manquantes avec une valeur égale à -999 ???

    j'ai essayé avec des conditions if, etc mais je n'ai pas trouvé de solutions ...
    merci d'avance

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 375
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 375
    Points : 23 634
    Points
    23 634
    Par défaut
    Il y a plusieurs façons de le faire mais si c'est simplement occasionnel et que tu cherches la façon la plus « facile » de le faire, tu peux essayer avec join. Le problème vient du fait qu'il faut déjà générer une suite complète et contiguë de dates vaildes, en tenant comptes des années bissextiles, etc. Pour cela, tu peux exploiter les possibilités offertes par date.

    Sous Bash, commence par générer une suite de dates valides au format que tu utilises dans ton fichier :

    Code Shell : Sélectionner tout - Visualiser dans une fenêtre à part
    $ for i in {5000..1} ; do date "$i day ago" +'%Y%m%d' ; done > datesvalides.txt

    Le « 5000 » est là pour dire que je remonte cinq mille jours en arrière, soit courant 1999 à la date où j'écris ce commentaire. Je ne sais pas s'il y a moyen de spécifier une date de départ ET de faire faire un calcul à « date », et ça me fatigue de chercher pour le moment. :-)

    Ensuite, tu utilises « join » pour faire une « jointure » entre tes deux fichiers, c'est-à-dire associer une ligne de l'un avec une ligne de l'autre en fonction d'un champ commun et de même valeur. Il faut également passer un paramètre pour effectuer une « jointure ouverte », c'est-à-dire toujours intégrer la ligne d'un fichier donné même si elle n'existe pas dans l'autre :

    Code Shell : Sélectionner tout - Visualiser dans une fenêtre à part
    $ join -a1 datesvalides.txt tonfichier.txt > resultatintermedaire.txt

    À ce stade, tu devrais avoir la liste complète des dates, la plupart du temps vides, avec les bonnes valeurs si elles existent.

    Tu utilises enfin « sed » pour reconnaître les lignes vides (uniquement la date donc), et les transformer en ligne avec la date suivie « -999 » :

    Code Shell : Sélectionner tout - Visualiser dans une fenêtre à part
    $ sed -e "s/\([[:space:]]*[0-9]\+[[:space:]]*\)$/\1 -999/g" resultatintermediaire.txt > resultatfinal.txt

    Et tu devrais obtenir ce dont tu as besoin. Deux remarques cependant :

    • Vérifie si tes fichiers utilisent des espaces ou des tabulations comme séparateurs ;
    • Les « jointures » sont la pierre angulaire des bases de données et elles sont extrêmement courantes en informatique. Beaucoup de scientifiques travaillant dans les laboratoires ou centres de recherche, et ayant un petit bagage informatique sans en faire leur métier y sont souvent confrontés. Généralement, ces gens-là commencent avec Excel puis, arrivés à ce stade, essaie de se débrouiller à coups de VLOOKUP.


    Si tu es dans la deuxième situation et si tu as beaucoup de données à traiter de la sorte, je t'encourage à te tourner à terme vers les bases de données et apprendre le SQL si tu ne le connais pas encore. Par la suite, soit tu utilises une suite bureautique adaptée comme Access ou OObase, soit tu te fais une mini base de données dans ton /home avec « sqlite », qui est très à la mode, soit tu montes une vraie base de données avec MySQL ou PostgreSQL, ou tu demandes à ton administrateur système de le faire pour toi sur un de ses serveurs.

  3. #3
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 287
    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 287
    Points : 12 744
    Points
    12 744
    Par défaut
    Bonjour,

    La difficulté est sur la date, sous linux il y a cette syntaxe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ date --date="20001231 1 day" +%Y%m%d
    20010101
    $ date --date="20001231 1 day ago" +%Y%m%d
    20001230
    Ce qui peut faciliter ton algorithme.
    Voici un exemple qui fonctionne mais on peut largement mieux faire, car celui-ci traite au minimum 3 fois la taille du fichier.
    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
    $ cat glop.txt
    20001212 5
    20001228 5
    20001229 4.3
    20001230 25.2
    20001231 32
    $ DEB=$(head -1 glop.txt | cut -d' '  -f1) ; FIN=$(tail -1 glop.txt | cut -d' ' -f1) ;( while [ "$DEB" != "$FIN" ]; do DEB=$(date --date="$DEB 1 day" +%Y%m%d); echo "$DEB -999"; done && sed -n 'p;s/ .*/ -999/p' glop.txt ) | sort | uniq -u
    20001212 5
    20001212 -999
    20001213 -999
    20001214 -999
    20001215 -999
    20001216 -999
    20001217 -999
    20001218 -999
    20001219 -999
    20001220 -999
    20001221 -999
    20001222 -999
    20001223 -999
    20001224 -999
    20001225 -999
    20001226 -999
    20001227 -999
    20001228 5
    20001229 4.3
    20001230 25.2
    20001231 32
    Cordialement.

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 552
    Points : 19 392
    Points
    19 392
    Par défaut
    Citation Envoyé par disedorgue
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    20001212 5
    20001212 -999
    ?
    aussi, pourquoi un sous-interpréteur (( while...)? des accolades ne suffisent pas ?

    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
    #!/usr/bin/awk -f
    function JplusUn(d){
          Y=substr(d,1,4)
          M=substr(d,5,2)
          D=substr(d,7,2)
    lendemain = strftime("%Y%m%d",mktime(Y" "M" "D" 00 00 00")+24*60*60)
    }
    function exist(){
       print $0
       JplusUn($1)
    }
    {
       if(FNR==1){
          exist()
       }else{
          if($1 > lendemain){
             while($1 > lendemain){
                print lendemain,"-999"
                JplusUn(lendemain)
             }
          }
       exist()
       }
    }
    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
    $ cat plop.txt
    cat glop.txt
    20001212 5
    20001228 5
    20001229 4.3
    20001230 25.2
    20001231 32
    $ ./script.awk
    20001212 5
    20001213 -999
    20001214 -999
    20001215 -999
    20001216 -999
    20001217 -999
    20001218 -999
    20001219 -999
    20001220 -999
    20001221 -999
    20001222 -999
    20001223 -999
    20001224 -999
    20001225 -999
    20001226 -999
    20001227 -999
    20001228 5
    20001229 4.3
    20001230 25.2
    20001231 32
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  5. #5
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 287
    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 287
    Points : 12 744
    Points
    12 744
    Par défaut
    Citation Envoyé par N_BaH Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    20001212 5
    20001212 -999
    ?
    Ok, bien vue , j'ai corrigé l'erreur (en rouge).

    aussi, pourquoi un sous-interpréteur (( while...)? des accolades ne suffisent pas ?
    Et en prenant en compte ta remarque cela donne (je n'ai pas oublié le ";" avant l'accolade fermante ):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     DEB=$(head -1 glop.txt | cut -d' '  -f1) ; FIN=$(tail -1 glop.txt | cut -d' ' -f1) ;{ echo "$DEB -999" ; while [ "$DEB" != "$FIN" ]; do DEB=$(date --date="$DEB 1 day" +%Y%m%d); echo "$DEB -999"; done && sed -n 'p;s/ .*/ -999/p' glop.txt; } | sort | uniq -u
    A l'origine de ma réponse, c'était juste de fournir la syntaxe sur l'incrémentation de la date, le code ici est, si on peut dire "ludique", mais, en mon sens, c'est juste pour du "one shot".
    Il aurait été aussi appréciable que dg1234 nous montre ce qu'il avait déjà fait
    Cordialement.

Discussions similaires

  1. [AWK-BASH] Vérification dans un fichier
    Par seanbean dans le forum Linux
    Réponses: 3
    Dernier message: 12/12/2010, 02h28
  2. Script bash - besoin d'aide avec sed & awk
    Par Obiwan31 dans le forum Unix
    Réponses: 1
    Dernier message: 23/04/2010, 10h11
  3. awk bash quotes syntaxerror
    Par aieaieaie dans le forum Shell et commandes GNU
    Réponses: 4
    Dernier message: 29/10/2009, 21h00
  4. [bash] utilisation de CAT/AWK pour parser un fichier CSV
    Par arnaudperfect dans le forum Shell et commandes GNU
    Réponses: 32
    Dernier message: 25/07/2007, 23h34
  5. probleme de récupération de variable en bash avec awk
    Par avogadro dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 24/12/2006, 01h31

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