Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1469 connectés 

  FORUM HardWare.fr
  Programmation
  Shell/Batch

  [Shell] If dans awk et histoire de NR

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Shell] If dans awk et histoire de NR

n°1922530
lapin_vert
Posté le 09-09-2009 à 12:56:58  profilanswer
 

Bonjour,

 

j'ai un fichier .csv construit ainsi:

 
Citation :

numero1 prov1 dest1 prot1a prot1b
numero2 prov2 dest2 dest2a prot2b
numero3 prov3 dest3 prot3
numero4 prov4 dest4 prot4a prot4b prot4c prot4d
numero5 prov5 dest5 prot5
numero6 prov6 dest6 prot6

 

Il n'y a jamais plus de 9 champs par lignes.

 

Le but de mon petit script serait de le modifier ainsi:

 
Citation :

numero1 prov1 dest1 prot1a
numero1 prov1 dest1 prot1b
numero2 prov2 dest2 prot2a
numero2 prov2 dest2 prot2b
numero3 prov3 dest3 prot3
numero4 prov4 dest4 prot4a
numero4 prov4 dest4 prot4b
numero4 prov4 dest4 prot4c
numero4 prov4 dest4 prot4d
numero5 prov5 dest5 prot5
numero6 prov6 dest6 prot6

 

Le script que j'ai codé jusqu'ici a cette tête:

 
Code :
  1. awk '{
  2. if ( "$5" != 0)
  3. printf ($1";"$2";"$3";"$4";"$6";"$7";"$8";"$9"\n"$1";"$2";"$3";"$5";"$6";"$7";"$8";"$9"\n" )
  4. fi
  5. NR=NR-2
  6. }' fichier1 > fichier2;
 

Si la commande awk rencontre une ligne dont le 5e champ est non-nul alors la ligne est dupliquée selon le schéma ci-dessus. L'utilité du "NR=NR-2" est de "repasser" sur les lignes qui contiennent plus de 5 champs. C'est là où ça coince car cette dernière ligne ne fonctionne pas comme je le souhaiterai. Je suppose qu'il y a une subtilité, à moins que ça ne soit pas possible ?

 

Au final mon fichier2 est bien construit pour les lignes du fichier1 qui ne sont composées que de 5 champs au maximum. J'ai toutefois des lignes dans le fichier2 qui ont un 4e champ vide.


Message édité par lapin_vert le 09-09-2009 à 14:21:42
mood
Publicité
Posté le 09-09-2009 à 12:56:58  profilanswer
 

n°1923013
lapin_vert
Posté le 10-09-2009 à 16:26:02  profilanswer
 

Problème résolu.
 
Vraiment bête comme solution, le plus simple n'arrive pas toujours en 1er place dans mon esprit :D

Code :
  1. #Lecture du fichier ligne par ligne en affichant que 4 champs par ligne
  2. awk '{
  3. printf ( $1" "$2" "$3" "$4"\n"$1" "$2" "$3" "$5"\n"$1" "$2" "$3" "$6"\n"$1" "$2" "$3" "$7"\n"$1" "$2" "$3" "$8"\n"$1" "$2" "$3" "$9"\n" )
  4. }' fichier1 > fichier2;
  5. #Suppression des lignes qui ne sont pas composées de 4 champs et qui ont donc un espace en fin de ligne
  6. sed -i '/ $/d' fichier2;


 
Y'a du "gâchis" en copiant de nombreuses lignes qui ne contiennent pas de champs 4.
 
Le problème qui reste est que si de nouvelles lignes avec + de 9 champs font leur apparition le script va bugger mais en compter le nombre de champ maximum rencontré lors de la lecture du fichier on peut arranger le 4e champ avec une variable associée au nombre maximum de champs.
 
Si c'est pas clair et que vous souhaitez + d'info repostez sur ce topic.

n°1923021
gilou
Modérateur
Modzilla
Posté le 10-09-2009 à 16:40:47  profilanswer
 

Il y a une raison pour que ce soit en awk? En perl tu pourrais probablement avoir un truc qui marche sans limitation du nombre de champs.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°1923033
lapin_vert
Posté le 10-09-2009 à 16:51:31  profilanswer
 

gilou a écrit :

Il y a une raison pour que ce soit en awk? En perl tu pourrais probablement avoir un truc qui marche sans limitation du nombre de champs.
A+,


En effet j'aurai très bien pu faire ça en perl. Mais je me suis jamais penché sur ce langage. Je pensai que c'était un gain de temps de ne pas utiliser un langage inconnu pour moi et de me concentrer sur mes acquis si je voulais finir rapidement mon script.
 
Je sens que je vais quand même y jeter un oeil la prochaine fois. On se donne RDV dans la section perl :o :D

n°1923364
gilou
Modérateur
Modzilla
Posté le 11-09-2009 à 16:19:38  profilanswer
 

Pour parser des données formattées comme suit:

numero1;prov1;dest1;prot1a;prot1b
numero2;prov2;dest2;dest2a;prot2b
numero3;prov3;dest3;prot3
numero4;prov4;dest4;prot4a;prot4b;prot4c;prot4d
numero5;prov5;dest5;prot5
numero6;prov6;dest6;prot6


j'utiliserais ceci:

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Text::CSV;
  5.  
  6. my $sep = ';';
  7. my $csv = new Text::CSV({sep_char => $sep});
  8. my @f;
  9. while (<> ) {
  10.    if($csv->parse($_)) {
  11.        @f = $csv->fields();
  12.        if (scalar(@f) > 3) {
  13.            print join("\n", map {$f[0].$sep.$f[1].$sep.$f[2].$sep.$_} @f[3..scalar(@f)-1]), "\n";
  14.        }
  15.    }
  16. }


a la ligne 7, je crée un nouveau parser au format CSV
a la ligne 9, je récupère stdin ligne a ligne
a la ligne 10 et 11: une ligne est parsée et ses champs sont rangés dans un array
a la ligne 12 et 13: s'il y a plus de trois champs, je crée un sous-array qui démarre a partir du 4e champ, je concatène les 3 premiers champs de l'ancien array a chaque champ du sous-array, et j'imprime chaque champ ainsi modifié ligne à ligne.
 
Pour la ligne en entrée numero1;prov1;dest1;prot1a;prot1b  
après parsing, @f est un array a 5 éléments (numero1, prov1, dest1, prot1a, prot1b)
@f[3..scalar(@f)-1]) vaut donc (prot1a, prot1b)
$f[0].$sep.$f[1].$sep.$f[2].$sep vaut "numero1;prov1;dest1;"
map {$f[0].$sep.$f[1].$sep.$f[2].$sep.$_} @f[3..scalar(@f)-1] transforme donc  
(prot1a, prot1b) en (numero1;prov1;dest1;prot1a, numero1;prov1;dest1;prot1b) et il ne reste plus qu'a imprimer chaque élément de cet array comme une ligne, par du code standard (print join '\n',...).
A+,


Message édité par gilou le 11-09-2009 à 16:27:25

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°1923369
erulio
Posté le 11-09-2009 à 16:34:22  profilanswer
 

Code :
  1. awk 'NF>3{for (i=4;i<=NF; ++i) {print $1 " " $2 " " $3 " " $i}}' test.txt


Si j'ai bien compris [:doc petrus]

n°1923371
gilou
Modérateur
Modzilla
Posté le 11-09-2009 à 16:40:19  profilanswer
 

Excellent ça. Ça fait trop longtemps que je n'ai plus touché à awk pour me souvenir de sa syntaxe :o  
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°1923375
lapin_vert
Posté le 11-09-2009 à 17:32:22  profilanswer
 

Merci gilou pour ces explications. :jap:
 
Et merci erulio ta commande fonctionne impec' :love:  
 
Edith: c'est le NF>3 qui ne m'était pas venu à l'esprit. Ca fonctionne comme un if en fait ?  [:petrus75]

Message cité 1 fois
Message édité par lapin_vert le 11-09-2009 à 17:33:35
n°1923379
erulio
Posté le 11-09-2009 à 17:45:44  profilanswer
 

lapin_vert a écrit :

Edith: c'est le NF>3 qui ne m'était pas venu à l'esprit. Ca fonctionne comme un if en fait ?  [:petrus75]


C'est sans doute strictement identique à un if(NF<3) placé correctement. Donc en fait non, ça devait pas te gêner tant que ça :D

Message cité 1 fois
Message édité par erulio le 11-09-2009 à 17:47:26
n°1923382
lapin_vert
Posté le 11-09-2009 à 17:55:17  profilanswer
 

erulio a écrit :


C'est sans doute strictement identique à un if(NF<3) placé correctement. Donc en fait non, ça devait pas te gêner tant que ça :D


Ouai enfin y'a une marge entre ton  

Code :
  1. awk 'NF>3{for (i=4;i<=NF; ++i) {print $1 " " $2 " " $3 " " $i}}' test.txt


et mon

Code :
  1. awk '{
  2. if ( "$5" != 0)
  3. printf ($1";"$2";"$3";"$4";"$6";"$7";"$8";"$9"\n"$1";"$2";"$3";"$5";"$6";"$7";"$8";"$9"\n" )
  4. fi
  5. NR=NR-2
  6. }' fichier1 > fichier2;


 
:o


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Shell/Batch

  [Shell] If dans awk et histoire de NR

 

Sujets relatifs
script shell[shell/bash] - commande via SSH et variables
[shell] commande cat qui rajoute un retour chariotPROBLEME d'if comportant un lien
[Shell/Batch] Renommer des fichiers[Shell] Suppression retours à la ligne/retours chariot
Shell : besoin d'aide pour mon scriptTri shell d'une pile
Access : créer une condition If[Shell] Supprimer les répétitions de caractère
Plus de sujets relatifs à : [Shell] If dans awk et histoire de NR


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR