[Shell/Batch] Modification de valeurs non numériques dans une colonne

Modification de valeurs non numériques dans une colonne [Shell/Batch] - Shell/Batch - Programmation

Marsh Posté le 15-12-2010 à 14:29:59    

Bonjour à tous,
 
J’ai un petit problème sur lequel je bloque. Je souhaite pouvoir remplacer dans un fichier csv le champ d’une certaine colonne, par une valeur numérique fixe, lorsque celui-ci contient une valeur non numérique (càd avec au moins un caractère non compris entre [0-9]).  
 
Par exemple, si j’ai le fichier csv suivant :
 
A0001;B32;00000G1;20101010
A000201;B30;0000021;20101210
A0001;B3421;0000022;20101210
A0011103;B30;0000F22;20101210
A0001;B30;0000023;20101210
 
Je voudrais remplacer toutes les valeurs de la troisième colonne qui ne sont pas numériques par « 9999999999 » pour obtenir le fichier csv suivant :
 
A0001;B32;9999999999;20101010
A000201;B30;0000021;20101210
A0001;B3421;0000022;20101210
A0011103;B30;9999999999;20101210
A0001;B30;0000023;20101210
 
Cela est-il possible via awk ou sed ou tout autre outil et si oui quelle est alors la regexp ou l'instruction à utiliser ?
 
Merci d’avance pour vos solutions

Reply

Marsh Posté le 15-12-2010 à 14:29:59   

Reply

Marsh Posté le 15-12-2010 à 16:08:10    

Via une regexp, c'est sans doute possible, mais ce sera un peu compliqué.
 
Par contre, par awk, il est possible de le faire avec des if traditionnels assez simples.
 
Par exemple, il faudrait utiliser awk en lui indiquant que le séparateur est le point virgule (on supposera qu'il n'y a pas de point virgule à l'intérieur d'une chaine de caractères, mais que tous les points virgules sont des séparateurs de champs). Cela se fait, soit avec l'option -F, soit avec le mot clé FS de awk. Ensuite, il suffit de tester $3, puisqu'il s'agit de la troisième colonne, et de la laisser telle quelle ou de la changer.

Reply

Marsh Posté le 15-12-2010 à 16:52:55    

C'est pas forcément compliqué via une regex, et que tu sois en awk ou pas, tu es tout de même obligé d'y passer ;)

 

sans awk, tu peux faire un test comme ca :

Code :
  1. [ $(echo $line | awk -F';' '{print $3}' | grep -c "[^0-9]" ) -gt 0 ]


après te reste a redécouper la ligne, et remplacer le 3eme champ.

 

En awk c'est nettement plus élégant et plus rapide :

 
Code :
  1. awk -F';' -v OFS=';' '{if ($3~/[^0-9]/) {sub ($3,999999);print $0} else {print $0}}' fichier_csv


Message édité par Nukolau le 15-12-2010 à 17:35:00
Reply

Marsh Posté le 15-12-2010 à 17:47:24    

Merci à vous deux pour vos réponses. Cependant, quand j'essaye la 2ème commandes proposée, j'ai l'erreur suivante :
 
 
bash-3.00$ awk -F';' -v OFS=';' '{if ($3~/[^0-9]/) {sub ($3,999999);print $0} else {print $0}}' fichier.csv
awk: syntax error near line 1
awk: bailing out near line 1
 
Est-ce que j'ai oublié un truc ?

Reply

Marsh Posté le 16-12-2010 à 09:35:34    

Aïe, je n'avais pas fait attention à ca. Sur mon PC awk est lien sur gawk. il semble qu'en awk de base, les expressions régulières soient un peu différentes.
 
Je viens de tester avec oawk et ca fonctionne correctement.
 
Du coup, je ne sais pas te répondre, et j'avoue ne pas avoir trop le temps de chercher...

Reply

Marsh Posté le 20-12-2010 à 10:34:56    

Peut-être que l'option en awk normale serait FS... au lieu de OFS...
(Personnellement, j'ai toujours utilisé FS..., et je ne suis même pas sûr que cela soit utile, étant donné qu'on a déjà -F...)
Donc essayer :

awk -F';' '{if ($3~/[^0-9]/) {sub ($3,999999);print $0} else {print $0}}' fichier_csv


Mais, peut-être que le problème est ailleurs.
 


Message édité par olivthill le 20-12-2010 à 10:36:39
Reply

Marsh Posté le 20-12-2010 à 10:59:56    

Non en fait le OFS c'est le "output field separtor" qui sert à dire a awk de mettre des ; et non des espaces en sortie.

 

EDIT : après test, l'OFS n'est pas obligatoire avec un print $0

 

EDIT 2 : je viens de trouver une solution qui fonctionne sous awk standard, et également sous gawk. C'était bien le -v OFS qui ne fonctionnait pas, mais aussi le if...else et le sub qui ne semble pas exister en awk. Du coup j'ai supprimé les trois et ca fonctionne. On est quand même obligé de remettre le OFS sinon les lignes modifiées ne sont plus séparées par des ; mais des espaces alors que les autres restent bien avec des ;

 
Code :
  1. awk -F';' '{OFS=";"} ; $3~/[^0-9]/ {$3="99999"};{print $0}' fichier_csv

Message cité 1 fois
Message édité par Nukolau le 20-12-2010 à 11:45:39
Reply

Marsh Posté le 20-12-2010 à 19:32:24    

Ça fonctionne ça ? Il me semble que $0 correspond à la ligne entière d'origine, donc sans la modif sur $3. Du coup, t'es obligé de boucler entre $1 et $NF pour avoir la ligne entière mise à jour.

Reply

Marsh Posté le 21-12-2010 à 09:21:07    

Ca fonctionne sous awk sur une solaris 10 et en gawk sur une suse 10, je l'ai testé.
J'imagine que ca devrait fonctionner partout du coup.

Reply

Marsh Posté le 23-12-2010 à 09:28:13    

Nukolau a écrit :

Non en fait le OFS c'est le "output field separtor" qui sert à dire a awk de mettre des ; et non des espaces en sortie.
 
EDIT : après test, l'OFS n'est pas obligatoire avec un print $0
 
EDIT 2 : je viens de trouver une solution qui fonctionne sous awk standard, et également sous gawk. C'était bien le -v OFS qui ne fonctionnait pas, mais aussi le if...else et le sub qui ne semble pas exister en awk. Du coup j'ai supprimé les trois et ca fonctionne. On est quand même obligé de remettre le OFS sinon les lignes modifiées ne sont plus séparées par des ; mais des espaces alors que les autres restent bien avec des ;
 

Code :
  1. awk -F';' '{OFS=";"} ; $3~/[^0-9]/ {$3="99999"};{print $0}' fichier_csv



Merci beaucoup !
 
C'est génial, ça marche parfaitement avec ma version de awk  :bounce:

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed