Moulinette awk (ajout de champs) pour un newb [Résolu/Fermé]

Signaler
-
 matthieu -
Bonjour,
je ne suis pas du tout informaticien, ce qui explique que je bute deja sur ce probleme simplissime:
J'ai un fichier de taille variable, que je veux reecrire en rajoutant des lignes.
Ex:
j'ai le fichier ;

********
toto1
titi
********
toto2
tutu
********
toto3
tete
********

Je veux arriver a ca :

*******
toto1
totoajouté
titi
*******
toto2
totoajouté
tutu
********
(...)

Le probleme est que je ne connais pas a l'avance le nombre de partie entre lignes (******)
et mes connaissances en awk sont très basiques.
Je peux le faire en fortran, mais je trouve que awk est quand meme plus elegant et efficace dans une chaine en shell.

merci pour votre aide, et desole pour le niveau de la question!

7 réponses

Messages postés
18241
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
31 mai 2021
5 302
hello
$ cat a1
********
toto1
titi
********
toto2
tutu
********
toto3
tete
******** 
$ awk '{print $0} ; /^toto/ {print "totoajoute"}' < a1
********
toto1
totoajoute
titi
********
toto2
totoajoute
tutu
********
toto3
totoajoute
tete
******** 
$ 
merci dubcek pour ta reponse si rapide.
En fait, en voulant simplifier mon exemple, j'ai introduit un cas particulier.
Le nombre de ligne entre les ******** est toujours le meme, mais les champs peuvent etre differents (pas tous des "toto..." )
il s'agit pour etre precis de nom de substance (ex :

****
nitrate
.true.
0.0
*****
phosphate
.false.
0.0
*****

(...)

qui doit devenir par exemple

****
nitrate
nitrate
.true.
0.0
*****
(...)


Je pensais d'abord compter le nombre de substances (nb de lignees contenant **** -1)
puis faire une boucle a partir de la premiere occurence de "*****" (attention la ligne peut faire 20 "*")
je vois a peu pres comment faire, mais ce sont les "mots" qui me manquent !
desole pour cette mauvaise explication initiale

merci encore pour votre aide
Messages postés
18241
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
31 mai 2021
5 302
après toute ligne qui commence par 3 *, on lit la suivante et on l'imprime 2 fois
$ cat a1
****
nitrate
.true.
0.0
*****
phosphate
.false.
0.0
*****
choucroute
.true.
1.1

$ awk '{print $0} ; /^\*\*\*/ {getline ; print $0 ; print $0}' < a1
****
nitrate
nitrate
.true.
0.0
*****
phosphate
phosphate
.false.
0.0
*****
choucroute
choucroute
.true.
1.1
haha, merci pour la choucroute dubcek, on y est presque (faut etre patient avec les newb')
Quand on veut simplifier son probleme pour etre lu, on rajoute d'autre soucis

En fait,
je dois recopier nitrate, mais aussi rajouter 0.0 dans la 5eme ligne par exemple
(certains elements sont recopies, d'autres sont inseres)

****
nitrate
.true.
0.0
*****
(...)

doit donner (en resume)


****
nitrate
nitrate
.true.
.true.
0.0
1000.
*****
(...)


Ton script marche pour la premiere ligne apres ***, mais pour une autre ?
la commande getline est un peu obscure pour moi.

Merci de ton temps deja passe, je vais essayer de bidouiller a partir de tes infos, et la doc awk (c'est velu quand meme!)
Messages postés
18241
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
31 mai 2021
5 302
getline lit la ligne suivante, je peux faire:
 awk '{print $0} ; /^\*\*\*/ {getline ; print $0 "\n" $0 ; getline ; print $0 "\n" $0 "\n" "99.0" }' < a1
****
nitrate
nitrate
.true.
.true.
99.0
0.0
*****
phosphate
phosphate
.false.
.false.
99.0
0.0
*****
merci encore pour ta reactivite et ta patience (vu la clarte de mon expose)
Reste un dernier point que je vais essayer de corriger, vu tout ce que tu m'a donne

le fichier d'entree se termine par :

(...)
blabla
*************


et je voudrai qu'il se termine de la meme facon une fois reecrit, en fait que le script awk ne s'applique pas a la derniere occurence de ***** (sinon il recopie les blancs encore apres). C'est possible?
Je pensais supprimer les x dernieres lignes (toujours avec awk, une fois le script execute)

Quoiqu'il en soit, merci beaucoup, avec ca je me debrouillerai (j'allais partir dans des boucles for...!)
Messages postés
18241
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
31 mai 2021
5 302
il faut connaitre le nombre de lignes et on teste, si il y a égalité avec la ligne courante (NR) on sort

$ L=$(wc -l < a1)
$ awk '{print $0} ; /^\*\*\*/ {getline ; if (NR == '"$L"') exit ; print $0 "\n" $0 ; getline ; print $0 "\n" $0 "\n" "99.0" }' < a1
****
nitrate
nitrate
.true.
.true.
99.0
0.0
*****
phosphate
phosphate
.false.
.false.
99.0
0.0
*****
$ 
Messages postés
40805
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
10 août 2020
4 861
Salut,

Et avec "sed" (désolé dubcek ;-)) ) :

jp@MDK:~/tmpfs ssh$ cat fich
****
nitrate
.true.
0.0
*****
phosphate
.false.
0.0
*****
choucroute
.true.
1.1


jp@MDK:~/tmpfs ssh$ sed -i.bak '/\*\+/{n;/^$/q;s/.*/&\n&/;n;s/.*/&\n&\n99.0/}' fich

jp@MDK:~/tmpfs ssh$ cat fich
****
nitrate
nitrate
.true.
.true.
99.0
0.0
*****
phosphate
phosphate
.false.
.false.
99.0
0.0
*****
choucroute
choucroute
.true.
.true.
99.0
1.1


jp@MDK:~/tmpfs ssh$

;-))
merci a tous les deux, j'en ai assez pour m'en sortir !
Je vais essayer sed (pour le style), mais je trouve que pour un debutant comme moi, awk reste un peu plus comprehensible ! quoique on voit des similutudes dans la syntaxe.
Je ferme le sujet et merci pour tout
Messages postés
18241
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
31 mai 2021
5 302
on a pas besoin de compter les lignes, getline retourne 0 en cas d'eof
  $ awk '{print $0} ; /^\*\*\*/ {if(getline == 0) exit ; print $0 "\n" $0 ; getline ; print $0 "\n" $0 "\n" "99.0" }' < a1
tout reste dans le meme script encore mieux pour pas charger les scripts de lancement !
thanks again