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

Signaler
-
 teab -
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

2 réponses

Messages postés
40805
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
10 août 2020
4 808
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:~$

;-))
4
Merci

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

CCM 76687 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
Messages postés
40805
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
10 août 2020
4 808
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!
Messages postés
40805
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
10 août 2020
4 808
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
18238
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
21 novembre 2020
5 096
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
Messages postés
18238
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
21 novembre 2020
5 096
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?
Messages postés
18238
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
21 novembre 2020
5 096
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