Specifier numéro du champ, command sed ou awk

Résolu/Fermé
teab - Modifié par jipicy le 5/05/2010 à 10:38
 teab - 6 mai 2010 à 19:37
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

A voir également:

2 réponses

jipicy Messages postés 40842 Date d'inscription jeudi 28 août 2003 Statut Modérateur Dernière intervention 10 août 2020 4 894
30 avril 2010 à 17:00
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
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
0
jipicy Messages postés 40842 Date d'inscription jeudi 28 août 2003 Statut Modérateur Dernière intervention 10 août 2020 4 894
4 mai 2010 à 17:50
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$

;-))
0
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!
0
jipicy Messages postés 40842 Date d'inscription jeudi 28 août 2003 Statut Modérateur Dernière intervention 10 août 2020 4 894
5 mai 2010 à 10:16
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".
0
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!
0
dubcek Messages postés 18718 Date d'inscription lundi 15 janvier 2007 Statut Contributeur Dernière intervention 22 mars 2024 5 615
5 mai 2010 à 12:07
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
$ 
0
voila ce que je cherchais. Merci.
Il me manque juste la commande pour remplacer le fichier txt initial par celui modifié. J'ai essayé ce qui suit:

mon code:
cat toto.txt | awk -v c=4 'NR=4 {$c="newstr";print}' > toto.txt

mais le fichier toto.txt généré est vide.
Une idée?
0
dubcek Messages postés 18718 Date d'inscription lundi 15 janvier 2007 Statut Contributeur Dernière intervention 22 mars 2024 5 615
Modifié par dubcek le 5/05/2010 à 14:11
à la différence de l'option -i de sed, il faut passer par un autre fichier

awk -v c=4 'NR=4 {$c="newstr";print}' toto.txt > toto2.txt
mv toto.txt toto.bak ; mv toto2.txt toto.txt

attention : NR=4 : ne serait-ce pas plutot NR==4 si la ligne 4 ?
0
en effet, j'avais fait une faute de frappe, c'est bien ==.
Sinon j'aavais déjà essayé ta méthode, mais dans le fichier toto.txt je n'obtiens que la ligne modifiée.
0
dubcek Messages postés 18718 Date d'inscription lundi 15 janvier 2007 Statut Contributeur Dernière intervention 22 mars 2024 5 615
5 mai 2010 à 14:41
effectivement, le print ne s'applique qu'aux lignes modifiées, pour imprimer toutes les lignes, faire
awk -v c=4 'NR==4 {$c="newstr"}; {print}' toto.txt 
0
ok alors la en effet tout est écrit dans le fichier!
MAIS cette méthode engendre un problème.

Voici ma ligne type dans mon fichier toto.txt

1.96000E+03 0.00000E+00 0.00000E+00 | XX = f(Q HP etg.2)

En procédant comme tu me l'as précisé, l'espace de début de ligne est supprimé, les deux espaces entre les champs se transforment en un seul espace et le vide entre le dernier champ et le | également.
Or ce fichier doit être rigoureusement formatter de la même manière que celui d'origine.

As tu une astuce? Ou dois-je me lancer sur une toute autre piste?

Merci pour ton aide précieuse.
0