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

  FORUM HardWare.fr
  Programmation
  Shell/Batch

  [Shell] Remplacer des infos dans un fichier

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Shell] Remplacer des infos dans un fichier

n°1865703
Tonio94
Posté le 25-03-2009 à 15:14:21  profilanswer
 

Bonjour,
 
 
J'ai un fichier qui se présente comme ceci :
 
1|A
2|B
3|C
 
etc...
 
Comment remplacer une lettre (A, B ou C par exemple) dans le fichier par autre chose en faisant le moins d'étapes possibles ?
 
Actuellement je fais comme ceci :
- Je récupère le numéro de ligne (en fonction de la lettre)
- J'isole la ligne dans un fichier tmp
- Je supprime la ligne du fichier de départ
- Je remplace la lettre par une expression (dans le fichier tmp)
- Je copie la ligne obtenue à l'étape précédente dans le fichier de départ
- Et enfin je renomme le dernier fichier et supprime tous les tmp
 
J'appelle sed pour chaque étape et pour chaque étape j'ai au moins 1 fichier temporaire de créé. C'est pas forcément lourd mais c'est assez fastidieux...
 
C'est pourquoi je cherche une méthode plus simple pour remplacer directement dans le fichier ou éventuellement passer par UN SEUL fichier temp.
 
 
A vous... ;)
 
 
PS : C'est du bash (unix)

mood
Publicité
Posté le 25-03-2009 à 15:14:21  profilanswer
 

n°1865719
Elmoricq
Modérateur
Posté le 25-03-2009 à 15:50:53  profilanswer
 

perl -pi -e 's/\|A/|<remplacement>/;' <tonfichier>

n°1865779
Tonio94
Posté le 25-03-2009 à 16:52:15  profilanswer
 

Ok mais sed me fait la même chose (en 2 étapes mais en moins gourmand) avec sed -e 's/A/<remplacement>/g' <file>, mais si j'ai plusieurs 'A' dans mon fichier (mais d'index différent), ta commande remplace toutes les occurrences!
 
Il faudrait que je puisse passer un numéro de ligne ou bien l'index qui figure sur la ligne où la modification doit être effectuée.

n°1865782
Elmoricq
Modérateur
Posté le 25-03-2009 à 16:53:47  profilanswer
 

Tu ne veux supprimer que la première occurence du fichier ? Je ne comprends pas ce que tu cherches à faire (et l'avantage de perl, en plus d'avoir des regexp PCRE au lieu de POSIX, c'est qu'il modifie le fichier directement, ça te fait une étape de moins par rapport à sed... et côté gourmandise, comment dire... je doute que tu y vois une quelconque différence)


Message édité par Elmoricq le 25-03-2009 à 16:54:26
n°1865794
Tonio94
Posté le 25-03-2009 à 17:04:22  profilanswer
 

Oui possible pour le côté ressource.
 
En fait dans mon fichier je peux avoir ça :
 
1|A
2|B
3|A
4|C
5|E
6|A
 
Et je veux remplacer la lettre A de l'index 3 avec le moins d'étapes possible et en évitant de multiplier les fichiers temporaires.

n°1865813
Elmoricq
Modérateur
Posté le 25-03-2009 à 17:24:15  profilanswer
 

nawk -F'|' 'BEGIN{ OFS = "|"; } { if ($1 == "3" && $2 ~ "A" ) { $2 = "NEW"; } print $0; }' <fichier>  >  <nouveau fichier>
mv <nouveau fichier> <fichier>

 

ou

 

perl -pi -e 's/3\|A/3|NEW/;' <fichier>

 

ou

 

sed -e 's/3\|A/3|NEW/;' <fichier> > <nouveau fichier>
mv <nouveau fichier> <fichier>

 

Message cité 1 fois
Message édité par Elmoricq le 25-03-2009 à 17:25:33
n°1865844
Tonio94
Posté le 25-03-2009 à 18:00:41  profilanswer
 

Merci pour ta réponse Elmoricq !
 
La commande avec nawk me plait bien et fonctionne niquel :)

n°1866430
Sve@r
Posté le 26-03-2009 à 22:08:02  profilanswer
 

Elmoricq a écrit :

nawk -F'|' 'BEGIN{ OFS = "|"; } { if ($1 == "3" && $2 ~ "A" ) { $2 = "NEW"; } print $0; }' <fichier>  >  <nouveau fichier>
mv <nouveau fichier> <fichier>
 
ou bien  
 
sed -e 's/3\|A/3|NEW/;' <fichier> > <nouveau fichier>
mv <nouveau fichier> <fichier>


On peut même le faire en laissant le système gérer le fichier temporaire
 

Code :
  1. #!/bin/sh
  2. exec 3<fichier
  3. rm -f fichier
  4. nawk -F'|' 'BEGIN{ OFS = "|"; } { if ($1 == "3" && $2 ~ "A" ) { $2 = "NEW"; } print $0; }' 0<&3  >fichier
  5. # ou bien
  6. sed -e 's/3\|A/3|NEW/;' 0<&3 >fichier


Message édité par Sve@r le 01-04-2009 à 11:38:13

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1867274
matafan
Posté le 30-03-2009 à 09:13:54  profilanswer
 

Tu ne peux pas écrire dans le fichier que tu es en train de lire. Je peux me tromper mais je ne pense pas que le 0<&3 change quoi que ce soit au problème. Au final tu écris toujours dans le fichier que tu es en train de lire.
 
Edit : en fait tu as raison, ça marche. Le nouveau fichier a le même nom que l'ancien fichier mais un inode différent. Ca revient en quelque sorte à transformer le fichier initial en fichier temporaire, sauf qu'on n'a pas à s'embêter à trouver un nom qui va bien.

Message cité 1 fois
Message édité par matafan le 30-03-2009 à 09:57:48
n°1868193
Sve@r
Posté le 01-04-2009 à 11:36:57  profilanswer
 

matafan a écrit :

Tu ne peux pas écrire dans le fichier que tu es en train de lire. Je peux me tromper mais je ne pense pas que le 0<&3 change quoi que ce soit au problème. Au final tu écris toujours dans le fichier que tu es en train de lire.


Arf... faut tester ses théories avant de les écrire  :sol:  
 

matafan a écrit :

Edit : en fait tu as raison, ça marche. Le nouveau fichier a le même nom que l'ancien fichier mais un inode différent. Ca revient en quelque sorte à transformer le fichier initial en fichier temporaire, sauf qu'on n'a pas à s'embêter à trouver un nom qui va bien.


Tu as décrit effectivement le fonctionnement auquel je pense. Effectivement la création du canal 3 (ou d'un autre) doit se concrétiser quelque part par un inode qui va bien.
Au départ j'avais pensé que tout se faisait en mémoire mais quand j'ai testé et que j'ai vu que ça fonctionnait aussi avec des fichiers qui dépassaient le giga, j'ai abandonné cette idée...
 
J'ai un peu modifié mon post précédent car j'avais dit, à tord, que ça se faisait sans fichier temporaire alors qu'en réalité, il y a bien un fichier quelque part mais simplement on ne s'en préoccupe pas.


Message édité par Sve@r le 01-04-2009 à 11:39:22

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
mood
Publicité
Posté le 01-04-2009 à 11:36:57  profilanswer
 

n°1868417
Tonio94
Posté le 01-04-2009 à 17:31:14  profilanswer
 

Sur un korn shell ça me pond une erreur :
 

Code :
  1. ./script.sh[5]: 3: bad file unit number


 
Où 3 correspond au canal que je veux utiliser (comme dans l'exemple de Sve@r)
 
Une idée ?

n°1868433
Elmoricq
Modérateur
Posté le 01-04-2009 à 18:01:53  profilanswer
 

Le faire vieille mode dans un fichier temporaire avec un mv derrière ? [:opus dei]

n°1868611
Tonio94
Posté le 02-04-2009 à 10:34:51  profilanswer
 

Oui c'est déjà ce que je fais :)
 
Mais ça m'aurait permis d'économiser une étape :)

n°1868634
matafan
Posté le 02-04-2009 à 11:17:17  profilanswer
 

Il est moisi ton ksh, avec le miens ça marche bien (sous AIX).

n°1868696
Sve@r
Posté le 02-04-2009 à 14:34:10  profilanswer
 

Tonio94 a écrit :

Sur un korn shell ça me pond une erreur :
 

Code :
  1. ./script.sh[5]: 3: bad file unit number


 
Où 3 correspond au canal que je veux utiliser (comme dans l'exemple de Sve@r)
 
Une idée ?

matafan a écrit :

Il est moisi ton ksh, avec le miens ça marche bien (sous AIX).



 
Je l'aurais pas dit ainsi mais effectivement, j'étais sceptique sur le fait que ça ne fonctionne pas en ksh. J'ai tenté de tester ce matin mais nous n'avons plus de machine tournant sous ksh. Cependant ksh se voulant compatible shell, c'était assez bizarre que ça ne fonctionnat pas.
 
Petit détail: il ne faut pas d'espace entre le chiffre et le "<". Donc
exec 3 < fichier    => ne fonctionne pas
exec 3< fichier     => marche nickel
 

Elmoricq a écrit :

Le faire vieille mode dans un fichier temporaire avec un mv derrière ? [:opus dei]

Tonio94 a écrit :

Oui c'est déjà ce que je fais :)
 
Mais ça m'aurait permis d'économiser une étape :)



 
Sans approfondir sur le fait que c'est dommage de s'embêter à faire soi-même ce que le système fait déjà, gérer un fichier temporaire doit s'accompagner de précautions surtout contre le multi processus. Si le fichier temporaire est un bête "toto.txt" MAIS que le script est lancé plusieurs fois en parallèle, il risque d'y avoir un sacré chaos au niveau des infos contenues dans "toto.txt".
Obligation donc de s'occuper du
- nom du fichier temporaire qui doit être associé au processus=> utilisation de la variable "$$"
- nettoyage du fichier temporaire en fin de tâche
- nettoyage du fichier temporaire en cas d'interruption intempestive du script
Et là, ce qui semblait au début un truc tout con devient de suite plus délicat à gérer....


Message édité par Sve@r le 02-04-2009 à 14:45:31

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1869284
Tonio94
Posté le 03-04-2009 à 15:56:13  profilanswer
 

Et bien justement j'ai plusieurs exécutions de mon script en parallèle, et chaque exécution écrit dans le même fichier, pas forcément au même moment, mais ça peut arriver.
 
J'avais fait un oubli mais ça fonctionne bien sous mon ksh merci Sve@r :)
 
Par contre quel est le traitement effectué par exec ? Dans mon script je fais plusieurs nawk pour remplacer des références dans mon fichier, dois-je faire le exec et le rm avant chaque ou simplement au début de mon script (ce que j'imagine) ? Dsl pour la question bateau... :|

n°1869385
Sve@r
Posté le 03-04-2009 à 22:04:21  profilanswer
 

Tonio94 a écrit :

Par contre quel est le traitement effectué par exec ?


Ca te crée un canal numéroté en input (exec 3<fichier) ou output (exec 4>result) associé au fichier sus nommé.
 
Ensuite, lire le canal input (read line 0<&3) ou écrire dans le canal output (echo truc 1>&4) aura une répercussion sur le fichier associé au canal
 

Tonio94 a écrit :

Dans mon script je fais plusieurs nawk pour remplacer des références dans mon fichier, dois-je faire le exec et le rm avant chaque ou simplement au début de mon script (ce que j'imagine) ? Dsl pour la question bateau... :|


Le rm est là pour nettoyer le fichier avant d'y écrire dedans mais en fait, c'en est même inutile. Le exec tu le fais juste avant d'avoir besoin de lire le fichier !!!


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1869564
matafan
Posté le 04-04-2009 à 20:29:46  profilanswer
 

Non non, le rm est crucial, sans ça l'écriture se fait dans le fichier que tu es en train de lire (et tu finit probablement avec un fichier vide).
 
Ca veut dire aussi que tu ne peux pas utiliser cette méthode si tu as besoin de lire plusieurs fois le fichier initial, parce qu'après la première lecture le fd 3 est fermé, et à ce moment là les données s'envolent.

n°1870662
Tonio94
Posté le 07-04-2009 à 16:18:38  profilanswer
 

Effectivement j'ai testé et vérifié ! C'est propre comme méthode mais pas forcément pratique quand on a besoin d'écrire souvent dans le fichier et encore moins quand le même script le fait en parallèle.

 

Petite question sur la ligne suivante :

 
Code :
  1. nawk -F'|' 'BEGIN{ OFS = "|"; } { if ($1 == '$var' ) { $2 = '$new_value'; } print $0; }' file > tmp.file
 

J'aimerais savoir comment remplacer le "$2" qui représente le deuxième élement de mon fichier file par une variable qui contiendra le numéro de colonne.

 

Dans ce genre là :

 
Code :
  1. column="$2" ou column=`echo $2`
  2. nawk -F'|' 'BEGIN{ OFS = "|"; } { if ($1 == '$var' ) { $column = '$new_value'; } print $0; }' file > tmp.file
 

Car j'écris souvent cette même ligne et j'aimerais la mettre dans une fonction.

 


Merci.

Message cité 1 fois
Message édité par Tonio94 le 07-04-2009 à 16:19:15
n°1870683
Sve@r
Posté le 07-04-2009 à 16:53:02  profilanswer
 

matafan a écrit :

Non non, le rm est crucial, sans ça l'écriture se fait dans le fichier que tu es en train de lire (et tu finit probablement avec un fichier vide).


T'as raison (je viens de tester). Ceci dit, si le exec crée un fichier temporaire contenant la copie du fichier source, je m'explique mal que ça ne fonctionne que si la source a disparu. Ou alors le fichier est créé lors du rm. Bref il y a un manque dans mon raisonnement. Toutefois ça marche avec le rm et finalement c'est le principal.
 

Tonio94 a écrit :

Effectivement j'ai testé et vérifié ! C'est propre comme méthode mais pas forcément pratique quand on a besoin d'écrire souvent dans le fichier et encore moins quand le même script le fait en parallèle.


Arf évidemment si tu cherches les limites de la méthode, tu les trouves vite. Ceci dit, je vois mal l'utilité d'un script qui va écrire en parallèle (sous-entendu plusieurs fois) le fichier cible (qui sera donc le même à chaque fois)  :pt1cable:  
 

Tonio94 a écrit :

Petite question sur la ligne suivante :
 

Code :
  1. nawk -F'|' 'BEGIN{ OFS = "|"; } { if ($1 == '$var' ) { $2 = '$new_value'; } print $0; }' file > tmp.file


 
J'aimerais savoir comment remplacer le "$2" qui représente le deuxième élement de mon fichier file par une variable qui contiendra le numéro de colonne.


Ben te suffit de mettre "col=2" dans ton BEGIN puis demander "$col" qui correspondra alors au 2° mot. Et si tu veux que la valeur "2" puisse arriver depuis l'extérieur (le shell) faut utiliser "-v" lors de l'appel à awk (fonctionne avec les awk évolués comme gawk mais sans garantie pour nawk)
 

Code :
  1. nawk -vcol=2 -F'|' 'BEGIN{ OFS = "|"; } { if ($1 == '$var' ) { $col = '$new_value'; } print $0; }' file > tmp.file


Message édité par Sve@r le 07-04-2009 à 16:57:59

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1870726
matafan
Posté le 07-04-2009 à 17:27:19  profilanswer
 

en fait ce qui ce passe c'est ça :
 
1) Le "exec 3<fichier" ouvre le fichier et l'associe au fd 3
 
2) Le "rm fichier" supprime le fichier. Comme le fichier a encore des fd ouverts (notre fd 3), il est juste supprimé du répertoire, mais les données restent sur disque. D'ailleurs si on fait un du sur le répertoire qui contient le fichier, on voit que l'espace disque n'a pas été libéré, alors qu'on ne peut pourtant plus accéder au fichier par son nom.
 
3) Le "truc 0<&3 >fichier" crée un fichier "fichier". Ce fichier est un fichier comme un autre, qui n'a rien à voir avec le fichier initial, même s'il porte le même nom. D'ailleur sont numéro d'inode est différent du fichier initial. La commande lit les données du fd 3, qui sont les données "fantome" de notre fichier initial, qui n'existe plus mais qui a encore ses donées sur disque.
 
4) Quand truc a fini de lire le fd 3, le fd est fermé. A ce moment là il n'y a plus de fd associé au fichier initial, et ses données sont supprimées.
 
Donc il n'y a pas vraiment de fichier temporaire. Il y a juste les données du fichier initial, qui ne sont plus associées à un nom de fichier. C'est le mécanisme classique sous unix : quand un fichier est unlinké, il disparait du répertoire et on ne peut plus l'ouvir, mais ses données restent sur disque jusqu'à ce que le dernier fd associé au fichier ai été fermé.

n°1870738
Tonio94
Posté le 07-04-2009 à 17:40:51  profilanswer
 

Merci t'es un chef Sve@r ! ;)

 

On peut déclarer ce qu'on veut comme variable dans le BEGIN ?

 

Car j'essaie avec une modification de 2 colonnes mais il ne me fait que la 2e :

 
Code :
  1. nawk -F'|' 'BEGIN{ OFS = "|"; col1=2; col2=3 } { if ($1 == '$var' ) { $col1 = '$value1' && $col2 = '$value2'; } print $0; }' file > file.tmp
 

Et autre problème, quand je passe des valeurs numériques aucun soucis mais quand je passe une chaine de caractère à $value il ne m'écrit rien dans le fichier et écrase le contenu de la colonne (à l'emplacement de $var je précise).

 

Merci.

 


PS : Pour l'histoire du script lancé en parallèle, en fait il prend en paramètre des chemins différents donc chaque exécution n'analyse pas les mêmes fichiers, mais ils doivent par contre tous écrire dans un même fichier de log commun.

Message cité 1 fois
Message édité par Tonio94 le 07-04-2009 à 17:54:53
n°1870745
Tonio94
Posté le 07-04-2009 à 17:43:14  profilanswer
 

Merci pour l'explication détaillée matafan :)

n°1871051
Sve@r
Posté le 08-04-2009 à 13:16:20  profilanswer
 

matafan a écrit :


2) Le "rm fichier" supprime le fichier. Comme le fichier a encore des fd ouverts (notre fd 3), il est juste supprimé du répertoire, mais les données restent sur disque. D'ailleurs si on fait un du sur le répertoire qui contient le fichier, on voit que l'espace disque n'a pas été libéré, alors qu'on ne peut pourtant plus accéder au fichier par son nom.


Arf, non, pas chez-moi. Ma size a changé.
 

matafan a écrit :

3) Le "truc 0<&3 >fichier" crée un fichier "fichier". Ce fichier est un fichier comme un autre, qui n'a rien à voir avec le fichier initial, même s'il porte le même nom. D'ailleur sont numéro d'inode est différent du fichier initial.


Arf exact, le n° d'inode en fin de travail est toujours différent (alors que si on n'utilise pas de canal numéroté et qu'on s'amuse à effacer puis recréer le fichier, le n° d'inode ne change pas toujours)
 

matafan a écrit :

Donc il n'y a pas vraiment de fichier temporaire. Il y a juste les données du fichier initial, qui ne sont plus associées à un nom de fichier. C'est le mécanisme classique sous unix : quand un fichier est unlinké, il disparait du répertoire et on ne peut plus l'ouvrir, mais ses données restent sur disque jusqu'à ce que le dernier fd associé au fichier ai été fermé.


Joli !!! Et inversement si on ne fait pas le "rm", le nom de fichier n'est pas unlinké et est donc toujours associé à son contenu (ainsi que le canal 3) et donc écraser le fichier revient à perdre le contenu (et le canal 3 ne sert à rien). Excellent  :bounce:  
 
 

Tonio94 a écrit :

Merci t'es un chef Sve@r ! ;)
 
On peut déclarer ce qu'on veut comme variable dans le BEGIN ?
 
Car j'essaie avec une modification de 2 colonnes mais il ne me fait que la 2e :
 

Code :
  1. nawk -F'|' 'BEGIN{ OFS = "|"; col1=2; col2=3 } { if ($1 == '$var' ) { $col1 = '$value1' && $col2 = '$value2'; } print $0; }' file > file.tmp


 
Et autre problème, quand je passe des valeurs numériques aucun soucis mais quand je passe une chaine de caractère à $value il ne m'écrit rien dans le fichier et écrase le contenu de la colonne (à l'emplacement de $var je précise).
 
Merci.


Hum. Je ne suis pas un pro de awk mais je suis un peu dubitatif sur ta façon de faire. Il faut bien comprendre que les éléments $1 $2 $3 ne sont pas des variables (comme le $1 du shell) mais des mots de ta ligne (donc des valeurs de travail de awk) et donc j'ai un doute sur le fait que tu aies le droit de dire arbitrairement "$1=truc" alors qu'a l'origine, $1 a été prévu pour contenir autre chose. Ptet que tes problèmes viennent de là...
 
Tu ne peux pas faire plutôt l'inverse, c.a.d. récupérer $1, $2, $3 dans des variables bien à toi que tu pourras changer à ta guise si l'algo l'impose ???


Message édité par Sve@r le 08-04-2009 à 13:17:15

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1871126
Tonio94
Posté le 08-04-2009 à 14:59:55  profilanswer
 

En fait j'appelle souvent nawk de la même façon mais avec les valeurs et la position de colonne qui changent. Alors plutôt que de le répéter plusieurs fois dans mon code j'aimerais le mettre dans une fonction, dans ce style là :

 
Code :
  1. #!/bin/ksh
  2. function replace
  3. {
  4.   ref=$2
  5.   value=$3
  6.   nawk -F'|' 'BEGIN{ OFS = "|"; col='$1' } { if ($1 == '$ref' ) { $col = '$value'; } print $0; }' file > file.tmp
  7.   mv file.tmp file
  8. }
  9. replace 2 index1 2009
  10. # end
 

Écris de cette manière ça fonctionne (grâce à ton précèdent post), quand j'appelle la fonction replace le premier paramètre passé est "2" qui correspond au numéro de colonne à remplacer puis "index1" qui correspond à la réference/index (pour savoir à quelle ligne il faut remplacer) et enfin "2009" qui est la valeur à écrire à cet emplacement.

 

Ensuite j'ai deux problèmes :
- Lorsque à la place de 2009 je veux passer une chaine de caractère, par exemple "test", dans ce cas nawk m'écrase la valeur à remplacer dans le fichier 'file' mais ne m'écrit pas la chaine à écrire.
- Lorsque je veux remplacer 2 valeurs d'un coup. A ce moment là je passe en paramètre 2 numéros de colonnes (au lieu d'un) et 2 valeurs à remplacer. Comme je l'ai écris dans mon exemple de code précèdent. Mais il ne me fait qu'un remplacement sur les deux :

 
Code :
  1. nawk -F'|' 'BEGIN{ OFS = "|"; col1=2; col2=3 } { if ($1 == '$var' ) { $col1 = '$value1' && $col2 = '$value2'; } print $0; }' file > file.tmp
 

(seulement col2 est mis à jour dans le file)

 


Je sais bien que $1, $2, $3, etc correspondent dans le shell aux arguments du script ou d'une fonction et que pour awk ils correspondent aux numéros des "colonnes". Mais dans mon cas la colonne où il y a la valeur à changer est souvent modifiée, dans ce cas je ne peux pas écrire en statique $1, $2, $3 dans ma ligne awk, il faut que je le passe en paramètre de ma fonction.

 

Je ne sais pas si c'est plus clair comme cela, en espérant que tu puisses me filer un coup de pouce ;) Merci

Message cité 1 fois
Message édité par Tonio94 le 08-04-2009 à 15:01:49
n°1871484
Sve@r
Posté le 09-04-2009 à 13:16:14  profilanswer
 

Tonio94 a écrit :

En fait j'appelle souvent nawk de la même façon mais avec les valeurs et la position de colonne qui changent. Alors plutôt que de le répéter plusieurs fois dans mon code j'aimerais le mettre dans une fonction, dans ce style là :
 

Code :
  1. #!/bin/ksh
  2. function replace
  3. {
  4.   ref=$2
  5.   value=$3
  6.   nawk -F'|' 'BEGIN{ OFS = "|"; col='$1' } { if ($1 == '$ref' ) { $col = '$value'; } print $0; }' file > file.tmp
  7.   mv file.tmp file
  8. }
  9. replace 2 index1 2009
  10. # end


 
Écris de cette manière ça fonctionne (grâce à ton précèdent post), quand j'appelle la fonction replace le premier paramètre passé est "2" qui correspond au numéro de colonne à remplacer puis "index1" qui correspond à la réference/index (pour savoir à quelle ligne il faut remplacer) et enfin "2009" qui est la valeur à écrire à cet emplacement.


 
Je suis très étonné que cela fonctionne correctement vu que tu ne passes pas tes variables à awk. Tu appelles awk en laissant au shell le soin de remplacer "$value" par la valeur correspondante. Si tu rajoutes 'set -x" juste avant le awk, tu verras un truc ressemblant à ça

Code :
  1. nawk -F'|' 'BEGIN{ OFS = "|"; col=2 } { if ($1 == index1 ) { $col = 2009; } print $0; }' file > file.tmp


 

Tonio94 a écrit :

Ensuite j'ai deux problèmes :
- Lorsque à la place de 2009 je veux passer une chaine de caractère, par exemple "test", dans ce cas nawk m'écrase la valeur à remplacer dans le fichier 'file' mais ne m'écrit pas la chaine à écrire.


Hé oui. Il faudrait qu'il y ait écrit $col='test' or le nawk reçoit l'instruction $col=test (sans quotte). Ceci étant issu de la remarque ci-dessus
 
Voici ce que moi j'ai écrit

Code :
  1. #!/bin/sh
  2. function replace
  3. {
  4.     awk -F'|' -vcol=$1 -vref=$2 -vval=$3 'BEGIN{ OFS = "|" } { if ($1 == ref ) { $col = val; } print $0; }' file
  5. }
  6.  
  7. replace 3 index1 test
  8. # end


 
Et ça fonctionne totalement sur un fichier de ce style

Code :
  1. index1|toto|titi|tutu


 
Je me retrouve en sortie avec un fichier de ce style

Code :
  1. index1|toto|titi|test


 

Tonio94 a écrit :

Je sais bien que $1, $2, $3, etc correspondent dans le shell aux arguments du script ou d'une fonction et que pour awk ils correspondent aux numéros des "colonnes". Mais dans mon cas la colonne où il y a la valeur à changer est souvent modifiée, dans ce cas je ne peux pas écrire en statique $1, $2, $3 dans ma ligne awk, il faut que je le passe en paramètre de ma fonction.


Oui mais t'as oublié de les passer en tant que variables à awk !!!
 

Tonio94 a écrit :

- Lorsque je veux remplacer 2 valeurs d'un coup. A ce moment là je passe en paramètre 2 numéros de colonnes (au lieu d'un) et 2 valeurs à remplacer. Comme je l'ai écris dans mon exemple de code précèdent. Mais il ne me fait qu'un remplacement sur les deux :
 

Code :
  1. nawk -F'|' 'BEGIN{ OFS = "|"; col1=2; col2=3 } { if ($1 == '$var' ) { $col1 = '$value1' && $col2 = '$value2'; } print $0; }' file > file.tmp


 
(seulement col2 est mis à jour dans le file)


Faudrait pouvoir passer un tableau à awk et ça, suis pas certain qu'on puisse faire.
 
Moi pour faire ça je ruse en écrivant une boucle dans la fonction pour traiter chaque remplacement

Code :
  1. #!/bin/sh
  2. function replace
  3. {
  4.     ref=$1; shift
  5.  
  6.     for item in $*
  7.     do
  8.         col=`echo $item |cut -f1 -d:`
  9.         val=`echo $item |cut -f2 -d:`
  10.  
  11.         exec 3<file
  12.         rm -f file
  13.         awk -F'|' -vcol=$col -vref=$ref -vval=$val 'BEGIN{ OFS = "|" } { if ($1 == ref ) { $col = val; } print $0; }' 0<&3 >file
  14.     done
  15. }
  16.  
  17. replace index1 2:x 3:y 4:z
  18. # end


 
Et ça fonctionne totalement sur un fichier de ce style

Code :
  1. index1|toto|titi|tutu


 
Je me retrouve en sortie avec un fichier de ce style

Code :
  1. index1|x|y|z


 
Bien entendu, tout ça sous bash+gawk Linux car j'ai pas ksh+nawk pour tester...


Message édité par Sve@r le 09-04-2009 à 13:17:21

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1876206
Tonio94
Posté le 22-04-2009 à 11:39:58  profilanswer
 

Merci pour ta contribution c'est top ! je vais mettre tout ça en application ! (dsl pour le temps de réaction, retour de vacances!) ;)
 
Tant qu'on est sur awk, un truc tout simple qui ne fonctionne pas et je ne vois pas pourquoi :
 

Code :
  1. FILE=file.tmp
  2. VALUE=toto
  3. INFO=`nawk -F'|' 'BEGIN{ OFS = "|"; } { if ($1 == '${VALUE}' ) { print $2; } }' $FILE`
  4. echo $INFO


 
Il n'y a rien dans $INFO.... :|
 
Alors que si je tappe la ligne nawk directement dans le shell en remplaçant les variables par leurs valeurs, ça fonctionne o_o
 
Contenu du fichier scanné :
toto-1|titi-1|tata-1
toto-2|titi-2|tata-2
etc.
 
 
Si tu as une idée je sèche, j'ai fait autrement avec sed en attendant mais c'est plus long :\

Message cité 1 fois
Message édité par Tonio94 le 22-04-2009 à 11:47:18
n°1878313
Sve@r
Posté le 27-04-2009 à 14:53:34  profilanswer
 

Tonio94 a écrit :

Merci pour ta contribution c'est top ! je vais mettre tout ça en application ! (dsl pour le temps de réaction, retour de vacances!) ;)
 
Tant qu'on est sur awk, un truc tout simple qui ne fonctionne pas et je ne vois pas pourquoi :
 

Code :
  1. FILE=file.tmp
  2. VALUE=toto
  3. INFO=`nawk -F'|' 'BEGIN{ OFS = "|"; } { if ($1 == '${VALUE}' ) { print $2; } }' $FILE`
  4. echo $INFO


 
Il n'y a rien dans $INFO.... :|
 
Alors que si je tappe la ligne nawk directement dans le shell en remplaçant les variables par leurs valeurs, ça fonctionne o_o
 
Contenu du fichier scanné :
toto-1|titi-1|tata-1
toto-2|titi-2|tata-2
etc.
 
 
Si tu as une idée je sèche, j'ai fait autrement avec sed en attendant mais c'est plus long :\


 
T'as toujours pas appris à passer une variable à awk ? J'en ai pourtant parlé 2 fois !!!
 

Code :
  1. FILE=file.tmp
  2. VALUE=toto
  3. INFO=`nawk -F'|' -vval=$VALUE 'BEGIN{ OFS = "|"; } { if ($1 == val ) { print $2; } }' $FILE`
  4. echo $INFO


 
C'est pas bien de mettre ses variables en majuscule. Les majuscules sont réservées aux variables système (PATH, HOME, etc)


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1889014
Tonio94
Posté le 28-05-2009 à 14:59:55  profilanswer
 

Autant pour moi :\
 
Merci encore Sve@r pour ta précieuse aide ! :)

n°1889821
Sve@r
Posté le 30-05-2009 à 19:44:34  profilanswer
 

Tonio94 a écrit :

Autant pour moi :\
 
Merci encore Sve@r pour ta précieuse aide ! :)


 
Hey, 30 jours plus tard !!!???!!!
 
Enfin vieux motard...  :sol:


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1890839
Tonio94
Posté le 03-06-2009 à 13:58:14  profilanswer
 

Sve@r a écrit :


 
Hey, 30 jours plus tard !!!???!!!
 
Enfin vieux motard...  :sol:


 
 
Disons qu'entre temps j'avais fait un truc avec sed - un peu crade - qui fonctionnait et je n'étais pas repassé par là.
 
Mais je pense que ce thread pourra en aider plus d'un ! ;)

mood
Publicité
Posté le   profilanswer
 


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

  [Shell] Remplacer des infos dans un fichier

 

Sujets relatifs
Création macro pour un fichier Excel de 600p et 13000 lignesfonction en PHP4 vèrifiant la validitè d'un fichier XML selon DTD
[BATCH] automatiser changement de nom de fichierAPI en PHP4 qui crée un fichier XML respectant un DTD donnée
VB Sauvegarder fichier avec droits adminScript shell pour récupèrer des images sur une camera
Lire et convertir un fichier .luw[résolu] Création de dossier
Upload de fichier en phpCopie avec renommage de Fichier. batch DOS
Plus de sujets relatifs à : [Shell] Remplacer des infos dans un fichier


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