Forum Programmation.shell aide avec awk

Posté par  .
Étiquettes : aucune
0
1
mar.
2006
Bonsoir tout le monde!
J'ai un probleme pour implémenter mon script; vous pouvez vous en doutez en fait :) Je m'explique, en précisant que je n'ai jamais fait de script shell jusqu'à aujourd'hui, mais j'en ai besoin pour mon boulot :(

J'ai un tableau dans un fichier texte "sacinfo.txt" de 13 colonnes, avec + de 5000 lignes. Chaque colonne est séparée par une tabulation, on obtient un truc du style:

040414_230739 12.200000 71.669998 -7.747000 2004 105 23 12 26.125000 GUA 27.489021 -286.184998 10801.168513

pour une des lignes. (Il y a une double tabulation entre 26.125 et GUA)

Je souhaite que mon script lise pour chaque ligne les variables 2 et 12 (en l'occurence 12.2 et -286.184998).
Ensuite je veux qu'il appelle un programme et passe en parametre de ce programme mes deux variables. Le programme s'appelle ttimes et s'execute dans le shell. Je montre ici juste un extrait de ce que affiche ttimes, et de ce qui m'interesse:

Enter delta: delta # code time(s) (min s) dT/dD dT/dh d2T/dD2



60.00 1 P 607.81 10 7.81 6.8772 -1.61E-01 -4.20E-03

2 pP 608.77 10 8.77 6.8787 1.61E-01 -4.20E-03

Je ne sais pas si une fois posté le message formattera correctement mon texte, mais on a ici les lignes 35, 36, 37 et 38. Ce qui m'interesse est le premier nombre après P: 607.81.
Enfin je veux qu'il recupère un des résultats du programme ttimes, pour l'ajouter dans une nouvelle colonne (soit une 14e colonne) dans mon fichier "sacinfo.txt". Difficile? Du moins pour moi qui débute oui, mais j'ai réussi à réaliser certaines parties. Cependant dès que je relie le tout, mon script me met une erreur dès la ligne deux.

Voici mon script:

#!/bin/sh

awk -F "\t" '{if($2=="Profondeur") next;

else ttimes << EOF >ttpsav

P



$2

$12

-1

-1

EOF;

awk 'NR==37 {print $4>}'~/ttpsav>~/ttp}'~/sacinfo.txt

Je l'explique: en premiere ligne, j'échappe la premiere ligne de mon tableau dans sacinfo qui contient le titre des colonnes (a priori ça marche).
Ensuite, j'invoque ttimes, je rentre les commandes (elles sont bonnes), et j'enregistre le résultat dans ttpsav.
Puis je me place en 37e ligne de ttpsav, je récupere la 4e variable (c'est la bonne) et je l'enregistre dans un fichier nommé ttp. Je ne gere pas ici l'ecriture dans la 14e colonne du fichier sacinfo.txt car ce serait une cerise sur le gateau, si j'ai le gateau déjà je serais content!
Qu'en pensez vous? ai je le droit d'invoquer deux fois awk l'un dans l'autre? Mon erreur m'indique que ttpsav est introuvable. Mais meme si ce probleme se resoud je ne sais pas si mon script est correct. Je ne suis plus au boulot là (heureusement remarque) donc je peux pas le lancer.

Merci si vous prennez le temps de tout lire, j'ai été le plus explicite possible! En esperant qu'il existe une solution, sinon je devrais le faire en C mais je ne sais pas comment on invoque un programme shell dans un programme c :( :p

Bonne soirée!
  • # un essai

    Posté par  . Évalué à 2.

    Est-ce que quelque chose dans ce genre ne pourrait pas marcher :
    $ for var in "$(awk -F "\t" '{if (NR != 1) {print $2" "$12}}' sacinfo.txt)"; do echo "P $var -1 -1" | ttimes | awk '{if (NR==37) {print $4}}'; done

    Pour ce qui concerne ta dernière colonne, peut-être que paste peut faire l'affaire :
    $ for var in "$(awk -F "\t" '{if (NR != 1) {print $2" "$12}}' sacinfo.txt)"; do echo "P $var -1 -1" | ttimes | awk '{if (NR==37) {print $4}}' >> /tmp/tmp.txt; done
    $ paste sacinfo.txt /tmp/tmp.txt > sacinfo.new.txt


    PS: Devrait fonctionner sous bash, sinon, il devrait suffire de modifier la structure du for. Ne pas oublier non plus les ". Et enfin, tout ça n'a pas été testé et peut-être que je n'ai pas très bien tout compris ce qu'il y avait dans tes fichiers et ce que fait ton programme ttimes.

    En espérant que ça t'aide quand même...
    • [^] # Re: un essai

      Posté par  . Évalué à 1.

      Ouf! Merci d'avoir eu la patience de me lire, car ta réponse m'a énormément aidé! En décorticant ce que tu proposais, j'ai pu comprendre pas mal de choses, notamment la notion de pipe! C'est vraiment astucieux! J'ai pourtant l'habitude de programmer mais je me suis fais un peu surprendre par la programmation shell. Celui qui la maitrise completement est le roi du pétrole!

      J'y ai presque repassé la journée, mais en m'inspirant de ta solution, j'ai réécrit le script en comprenant ce que je faisait. Pour ceux que ça interesse, voilà ma solution (mais je pense qu'il y en a bcp, plus performantes):

      #!/bin/sh
      i=1
      nbline=`cat ~/sacinfo.txt | wc -l`
      rm -f ~/sacinfo.new.txt
      echo "Tps ondes P" >> ~/tmp.txt
      while [ "$i" != "$nbline" ]
      do
      ((i+=1))
      ttp=`awk -F "\t" 'NR == '$i' {printf "P\n\n%s\n%s\n%d\n%d\n",$2,$12,-1,-1}' ~/sacinfo.txt | ttimes | awk 'NR == 37 {printf $4}'`
      echo "$ttp" >> ~/tmp.txt
      done
      paste ~/sacinfo.txt ~/tmp.txt > ~/sacinfo.new.txt
      rm -f ~/tmp.txt

      Explications:
      J'ai un compteur de ligne de mon fichier sacinfo.txt qui est "i". La boucle while parcourt toutes les lignes afin que le premier awk traite mon fichier ligne par ligne. Le printf formate les données avec des retours chariots pour les entrer dans ttimes. Le résultat de ttimes est renvoyé dans un awk qui va chercher le bon nombre en ligne 37 à la 4e position. Le tout est enregistré dans une variable ttp qui est redirigé ensuite dans un fichier: tmp.txt.
      A la fin de la boucle j'ai donc un fichier tmp.txt qui contient une colonne nommée "Tps ondes P" (fait au début du script). La commande paste colle directement cette colonne après les autres colonnes de mon fichier sacinfo.txt (je trouve ça vraiment très fort).

      Encore merci pour la réponse! C'est super puisque j'ai perdu deux jours, mais gagner peut etre 2 semaines et appris pas mal de choses :)
      • [^] # Re: un essai

        Posté par  . Évalué à 1.

        Bon, ton script m'a permis de mieux comprendre la question de départ et je me permet donc de mettre une version corrigée de mon premier script (même si finalement tu as déjà trouvé ta réponse).

        #!/bin/sh

        echo "Tps ondes P" > /tmp/tmp.txt

        # Récupération des champs 2 et 12 de chaque ligne de `sacinfo.txt'
        # On les concatène avec un caractère de séparation dont on est sûr qu'il
        # ne figure pas dans ces champs (ici `@'). Ca permet de faire des deux
        # champs une seule variable pour la boucle `for' et donc un traitement
        # par `pipe' sur chaque couple de champs. Le `@' est supprimé avec `sed'
        # pour récupérer les deux champs par la suite.
        for var in `awk -F "\t" '{if (NR != 1) {print $2"@"$12}}' sacinfo.txt`; do
             echo -ne "P\n\n$var\n-1\n-1\n" \
             | sed -e "s/@/\n/" \
             | ttimes \
             | awk '{if (NR==37) {print $4}}' >> /tmp/tmp.txt
        done

        paste sacinfo.txt /tmp/tmp.txt > sacinfo.new.txt

        rm -f /tmp/tmp.txt


        Évidemment, je n'ai pas testé mais sauf erreurs ça devrait fonctionner tel quel. Logiquement ça devrait aussi être plus rapide que ta version où tu fais autant de traitement de sacinfo.txt par `awk' que le fichier ne comprend de lignes (ce qui doit être pas mal bourrin, surtout si sacinfo.txt comprend beaucoup de lignes).
        Par contre, ma version est un peu grouiik avec ce bidouillage de `@', mais bon, on ne peut pas tout avoir !

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.