Specifier numéro du champ, command sed ou awk [Résolu/Fermé]

-
Bonjour à tous,

Une petite question concernant la commande sed.
Voila mon problème. J'ai un fichier texte (toto.txt) qui contient 3 colonnes de nombres. Je dois remplacer à la ligne N (=15 par ex) le champ 3 par une chaine que je noterai newstr. Le champ 3 est une chaine que j'appelle oldstr.
fichier: str1 str2 oldstring

Jusqu'à présent, je faisais:
sed -i '15 s/oldstr/newstr/' toto.txt

resultat --> str1 str2 newstring

donc cela marche très bien sauf si le champ 2 a la même valeur que le champ 3:

fichier: str1 oldstr oldstr

Car dans ce cas il me remplace le champ 2.

Je sais qu'il existe de nombreuses solutions, mais j'en cherche une simple qui puisse alléger mon code; en indiquant juste le numéro du champ qui m'interesse (et que je connais a priori).

Merci d'avance!
teab

Afficher la suite 

2 réponses

Meilleure réponse
Messages postés
43480
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
18 novembre 2019
4616
4
Merci
Salut,

2 solutions. Si tu sais quelle occurrence remplacée, 1ère solution, si tu ne sais pas le nombre d'occurrences à l'avance, 2nd solution :

 jp@jp-kermic:~$ cat teab 
fichier: str1 str2 oldstr

fichier:str1 oldstr oldstr 

jp@jp-kermic:~$ sed 's/oldstr/newstr/2' teab 
fichier: str1 str2 oldstr

fichier:str1 oldstr newstr 

jp@jp-kermic:~$ sed 's/\(.*\)oldstr/\1newstr/' teab 
fichier: str1 str2 newstr

fichier:str1 oldstr newstr 

jp@jp-kermic:~$

;-))

Dire « Merci » 4

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

CCM 70282 internautes nous ont dit merci ce mois-ci

Tout d'abord merci!
Je ne connais effectivement pas l'occurence.
Donc je me suis tourné vers ta seconde méthode. Le problème est que j'ai besoin de spécifier la ligne dans la commande sed; si je la spécifie, et que je run mon script, toute la ligne est remplacée!

Erreur de ma part ou est-ce normal?
Que me conseillez-vous?

Cordialement,
teab
jipicy
Messages postés
43480
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
18 novembre 2019
4616 -
Tu dois surement faire une petite erreur :

jp@jp-kermic:~/trash/rep$ cat -n teab 
     1	fichier: str1 str2 oldstr
     2	fichier:str1 oldstr oldstr
     3	fichier: str1 str2 oldstr
     4	fichier:str1 oldstr oldstr
     5	fichier: str1 str2 oldstr
     6	fichier:str1 oldstr oldstr

jp@jp-kermic:~/trash/rep$ sed '4 s/\(.*\)oldstr/\1newstr/' teab | cat -n
     1	fichier: str1 str2 oldstr
     2	fichier:str1 oldstr oldstr
     3	fichier: str1 str2 oldstr
     4	fichier:str1 oldstr newstr
     5	fichier: str1 str2 oldstr
     6	fichier:str1 oldstr oldstr

jp@jp-kermic:~/trash/rep$

;-))
Effectivement j'avais fait une erreur....donc ta méthode fonctionne.
Toutefois, elle me semble limitée. Je m'explique. Imaginons que j'ai en fait cette ligne:

4 olstr oldstr oldstr

Je veux cette fois remplacer uniquement le deuxième champ par newstr. C'est faisable avec la première méthode que tu avais proposé, mais cela m'oblige à rajouter une ligne de code en faisant une boucle conditionnelle. C'est pour ça que je cherchais une méthode qui me permettre de spécifier le numéro du champ et non de l'occurence.
Tu vois ce que je veux dire?
Si tu n'as pas mieux ce n'est pas grave, c'est déjà très bien!
jipicy
Messages postés
43480
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
18 novembre 2019
4616 -
Re-

une méthode qui me permettre de spécifier le numéro du champ et non de l'occurence.
Sed n'est pas fait pour ça ;-(
Sed est un éditeur de flux orienté ligne et non un éditeur de flux orienté champ. Pour ça il te faut te tourner vers "awk", qui lui est prévu pour traiter les "champs".
d'accord. C'est ce que j'avais commencé à faire, mais awk n'est pas facile à apprivoiser....
J'arrive à l'utiliser pour la lecture de fichier, mais pas pour le remplacement!
Messages postés
17943
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
21 novembre 2019
4511
0
Merci
hello
pour change partiellement ou entèrement un champ spécifique avec awk
$ echo olstr oldstr oldstr oldstr | awk -v c=3 '{sub("old", "new", $c);print}'
olstr oldstr newstr oldstr
$ 
$ echo olstr oldstr oldstr oldstr | awk -v c=2 '{sub("old", "new", $c);print}'
olstr newstr oldstr oldstr
$  
$ echo olstr oldstr oldstr oldstr | awk -v c=2 '{$c="newstr";print}'
olstr newstr oldstr oldstr
$ 
$ echo olstr oldstr oldstr oldstr | awk -v c=4 '{$c="newstr";print}'
olstr oldstr oldstr newstr
$ 
je n'ai pas bash sous la main pour tester. Mais en tout cas merci des efforts que tu fais!
teab
dubcek
Messages postés
17943
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
21 novembre 2019
4511 -
selon la doc, modifier un champ implique la reconstruction de $0 en séparant les champs par OFS. Je ne vois donc pas d'autre méthode que celle du post 15 quand les séparateurs sont des espaces
Bonjour,

Alors j'ai testé ce matin. Effectivement il y un décalage de champ!
Le | devient le champ 5 au lieu de champ 4. Cependant je ne travaille pas sur les champs au delà du champ 3 donc cette méthode convient tout à fait!

Donc un grand merci à toi et aussi à Jipicy.

Pour ceux qui rencontreraient mon problème, je remets le code que tu as proposé:

sed -e 's/ /;/g' toto.txt |  awk -v c=4 'BEGIN{FS=OFS=";"} ; NR==4 {$c="newstr"}; {print}' |sed -e 's/;/ /g' 



J'ai une dernière question.
En fait la chaine 'newstr' est contenue dans un tableau tab, à la case i. La chaine est un nombre: 1.3333E+02 par exemple.


En reprenant ton code, il devient:

sed -e 's/ /;/g' toto.txt |  awk -v c=4 'BEGIN{FS=OFS=";"} ; NR==4 {$c='${tab[i]}'}; {print}' |sed -e 's/;/ /g' 


Le problème c'est que la valeur qui apparait dans le fichier n'est plus l'écriture scientifique mais l'écriture normale du nombre soit 133,33.

Y A t-il un moyen de le forcer à écrire la chaine exacte?
dubcek
Messages postés
17943
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
21 novembre 2019
4511 -
mettre des " pour que awk le traite comme une chaine de caractère et ne convertisse pas
...{$c="'${tab[i]}'"}; {....
Dubcek, un grand merci!
Tout fonctionne.

Bonne continuation!
teab