Bonjour,
Je dois modifier plusieurs programmes sous UNIX (ajouter des lignes après certaines commandes). comment puis-je faire pour automatiser ces modifications ?
Version imprimable
Bonjour,
Je dois modifier plusieurs programmes sous UNIX (ajouter des lignes après certaines commandes). comment puis-je faire pour automatiser ces modifications ?
Bonjour,
Il nous faut plus d'informations si tu veux que l'on puisse t'aider !
- Est-ce que les commandes que tu cherches sont toujours les mêmes ?
- Combien y en a-t-il ?
- Est-ce que les lignes que tu souhaites ajouter sont toujours les mêmes ?
- Est-ce que les fichiers cibles sont tous au même endroit ?
- ...
Sinon, saches que
permet de créer un fichier "nouveau_fichier" qui sera une copie de "fichier origine" dans lequel on a remplacé "chaine_a_remplacer" par "nouvelle_chaine"Code:sed 's/chaine_a_remplacer/nouvelle_chaine/g' fichier_origine > nouveau_fichier
Donc en mettant quelques commandes de ce type dans un script, cela devrait te permettre de résoudre ton problème.
En fait on m'a parlé de l'outil awk pour faciliter les modif.
L'idée générale :
j'ai X fichiers (tous sous le même répertoire), qui contiennent des lignes de commandes (en pro*c) et je dois rajouter à la suite de ces lignes une ligne de commande supllémentaire (toujours la même).
Je sais pas si c'est clair, cà à l'air simple comme ça mais ???????
C'est pas encore très précis.
Qu'est ce que tu entends pas "à la suite" ?
A la fin de chacune des lignes de commande recherchées ?
Après le groupe de lignes recherché ?
A la fin des fichier contenant ces commandes ?
permet d'ajouter une ligne à la fin d'un fichier.Code:echo "message" >> fichier.txt
pour ajouter la ligne à tous les fichiers du répertoire courant (*).Code:
1
2
3 for i in *; do echo "message" >> fichier.txt done
C'est ça que tu veux ?
OK,
Je vais te décrire un exemple de ce que je veux réaliser.
j'ai plusieurs fichier .pc (a.pc, b.pc...)
dans ces fichier j'ai une ligne
qui se trouve dans le corps des fichiersCode:#include <gestimpr.h>
je veux ajouter après cette ligne
un autre exempleCode:#include<userprog.h>
J'ai une ligne
et je veux ajouter après cette ligneCode:EXEC SQL INCLUDE sqlca.h;
et ainsi de suiteCode:
1
2 EXEC SQL INCLUDE bmtmain.h;
Le fait est que j'ai énormément de fichiers à traiter, et que j'ai beaucoup de ligne à ajouter. Je pourrais le faire manuellement, mais c'est au risque d'oublier certaines lignes voire certains fichiers. C'est pourquoi je voudrais créer des scripts qui me permettent de faire ces ajouts sans erreur.
j'espère que tu pourras m'éclairer...
Essaye ça:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 if [ ! -f pc-org.tar ] then tar cf pc-org.tar *.pc || exit fi for file in *.pc do cp $file $file.org awk ' /#include <gestimpr.h>/ { print $0 print "#include <userprog.h>" continue } /EXEC SQL INCLUDE sqlca.h;/ { print $0 print "EXEC SQL INCLUDE bmtmain.h;" continue } { print $0 } ' < $file.org > $file done
Code:sed -i 's/#include <gestimpr.h>/&\n#include<userprog.h>/' *.pc
Code:sed -i 's/EXEC SQL INCLUDE sqlca.h;/&\nEXEC SQL INCLUDE bmtmain.h;' *.pc
Attention, "sed -i" n'est pas à ma connaissance portable (spécifique Gnu sed).
Il est cependant simple de passer par des fichiers temporaires comme je l'ai fait avec awk.
D'autre part, il est possible de faire toutes les modifs avec une seule commande sed:
Code:
1
2
3
4 sed \ -e 's/#include <gestimpr.h>/&\n#include<userprog.h>/' \ -e 's/EXEC SQL INCLUDE sqlca.h;/&\nEXEC SQL INCLUDE bmtmain.h;' file.pc
J'ai cru comprendre qu'il souhaitait deux commandes distinctes (vu que l'une parle de C et l'autre de SQL).
Et en effet, encore que de nombreux autres sed possèdent cette option (par exemple, le sed de BSD), l'option -i n'est pas portable. Mais si l'on veut être portable, il faut aussi se passer du \n, qui n'est pas reconnu partout.
(à condition encore, d'avoir un shell décent... sinon, il faut passer par un fichier...)Code:
1
2
3 sed '/#include <gestimpr.h>/a\ #include<userprog.h>\ '
Mais je trouve que le sed défini par posix est bien trop limité pour l'usage quotidien, et j'ai pris l'habitude d'utiliser les extensions de GNU. Je recommande d'ailleurs aux gens d'utiliser le GNU sed (ou autre sed de qualité) quand ils ont le choix. En utilisant des sed de mauvaise qualité, on passe à côté de beaucoup de choses utiles (option -i, caractères spéciaux et de nombreuses autres extensions).
pro*c, comme d'autres (sql-c) est un langage préprocessé qui inclus les deux syntaxes au sein de même fichiers source. http://fr.wikipedia.org/wiki/Pro*C
"\n" est reconnu par les sed POSIX compliants.Citation:
Et en effet, encore que de nombreux autres sed possèdent cette option (par exemple, le sed de BSD), l'option -i n'est pas portable. Mais si l'on veut être portable, il faut aussi se passer du \n, qui n'est pas reconnu partout.
Ce n'est pas le shell mais sed qui traite '\n' dans le cas décrit.Citation:
(à condition encore, d'avoir un shell décent... sinon, il faut passer par un fichier...)
Ca se discute.Citation:
Mais je trouve que le sed défini par posix est bien trop limité pour l'usage quotidien, et j'ai pris l'habitude d'utiliser les extensions de GNU. Je recommande d'ailleurs aux gens d'utiliser le GNU sed (ou autre sed de qualité) quand ils ont le choix. En utilisant des sed de mauvaise qualité, on passe à côté de beaucoup de choses utiles (option -i, caractères spéciaux et de nombreuses autres extensions).
Petite rectification dans le awk :
Mettre next au lieu de continue
+ test pour éviter d'insérer plusieurs fois la même ligne ;)
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 for file in *.pc do cp $file $file.org awk ' /#include <gestimpr.h>/ { print $0 getline if ($0 != "#include <userprog.h>") { print "#include <userprog.h>" } print $0 next } /EXEC SQL INCLUDE sqlca.h;/ { print $0 getline if ($0 != "EXEC SQL INCLUDE bmtmain.h;") { print "EXEC SQL INCLUDE bmtmain.h;" } print $0 next } { print $0 } ' $file.org > $file done
[QUOTE=BlaireauOne;2528120]Petite rectification dans le awk :
Mettre next au lieu de continue
+ test pour éviter d'insérer plusieurs fois la même ligne ;)[/code]
Heu ... tu ajoutes une complexité inutile. Les deux patterns ne risquent pas d'apparaitre sur la meme ligne donc next est ici inutile.
Il faut laisser continue qui sert justement à éviter d'insérer plusieurs fois la meme ligne.
Merci à tous pour vos indications. Le moins qu'on puisse dire, c'est que mon cas fait débat...
Je vais essayer de m'y retrouver dans tous cela.
Est-ce qu'il ne faut pas intégrer BEGIN et END dans le script
if [ ! -f pc-org.tar ]
then
tar cf pc-org.tar *.pc || exit
fi
for file in *.pc
do
cp $file $file.org
awk ' BEGIN
/#include <gestimpr.h>/ {
print $0
print "#include <userprog.h>"
continue
}
/EXEC SQL INCLUDE sqlca.h;/ {
print $0
print "EXEC SQL INCLUDE bmtmain.h;"
continue
}
{
print $0
}
END
' < $file.org > $file
done
Il ne sert à rien d'inclure un BEGIN et un END s'il n'y a aucune instruction a exécuter en debut ou in fin de traitement.
Pour répondre à ta question envoyée en message privé, le premier bloc d'instructions sert juste à faire un backup des fichiers originaux:
Code:
1
2
3
4
5
6
7
8
9
10
11 # si le fichier pc-org.tar n'existe pas if [ ! -f pc-org.tar ] then # on crée l'archive tar contenant tous # les fichiers ayant l'extension .pc du répertoire courant. # Si cette création d'archive échoue, on abandonne le script car # on n'a vraisemblablement pas le droit d'écrire dans le répertoire # courant, ou le disque est plein, etc ... tar cf pc-org.tar *.pc || exit fi
[QUOTE=jlliagre;2528621]D'après la doc et ma pratique,
- "continue" fait passer à l'itération suivante dans une boucle (je ne vois pas de boucle while ou autre dans le awk qui nous occupe :?)Je t'accorde que le test de présence d'enregistrements en doublon ajoute une complexité inutile (c'était pour montrer les possibilités de awk) ;)
- "next" sert à retourner au début de la procédure awk et passer à l'enreg. suivant.
http://www.shellunix.com/awk.html#break
break, continue
Break: sortie de boucle
Continue: commence une nouvelle itération de la boucle.
.../...
next, exit
Next: passe à l'enregistrement suivant. On reprend le script awk à son début
Exit: ignore le reste de l'entrée et execute les actions définie par END
Tu as raison. J'ai utilisé une construction archaique qui ne fonctionne qu'avec les awk originaux (awk et nawk sous Solaris par exemple, ou gawk --traditional) . Les continue doivent etre remplacés par des next dans mon script pour plus de portabilité via une conformité POSIX.
Coucou les gars,
J'ai bien pris note de toutes vos remarques et j'ai essayé de tester si le awk fonctionné sur un fichier.
J'ai donc un fichier test.pc et j'ai créé un .sh dans lequel j'ai mit le code suivant.
Résultat, le programme boucle et ne produit rien si ce n'est que je me retrouve avec des ^M à la fin de chaque ligne de mon programme test.pc. Je ne comprend pas. Est-ce que c'est modif sont du au transfert FTP que j'ai fait ?Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 for file in test.pc do cp $file $file.org awk ' /#include <gestimpr.h>/ { print $0 print "#include <userprog.h>" next } /EXEC SQL INCLUDE sqlca.h;/ { print $0 print "EXEC SQL INCLUDE bmtmain.h;" next } /char TcSortie[80];/ { print $0 print "char lib_err1[2000];" next } /EXEC SQL BEGIN DECLARE SECTION;/ { print $0 print "VARCHAR sessionid[21]," print "lib-err[2000]," print "paragraphe_err[80];" print "int cd_ret;" } { print $0 } ' < $file.org > $file done
Avez vous une piste.
Merci
Quel Unix utilises-tu ?
Il est très simple de supprimer ces ^M.
Qu'entend-tu par "boucle et ne produit rien" ?
Utilise les tags "code" pour que ton code soit plus lisible.
Il manque un next dans ton avant dernier bloc.
Le < est inutile et le nom du fichier doit apparaitre après le ' final, sur la meme ligne, pas la ligne suivante.
J'utilise AIX
Et quand je lance le script sh, il ne se passe rien. J'ai attendu un peu plus d'une minute et j'ai fait ^c.
Voilà ce que j'entend par bouclé
Il ne boucle donc pas, il ne fait rien. C'est à dire qu'il attend une entrée au clavier vu que tu ne lui passes pas de fichier à traiter.
Corrige ton script comme je l'ai indiqué dans mon post précédent.
J'ai apporté les modifs suivantes :
et j'ai maintenant l'erreur suivanteCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 for file in test.pc do cp $test.pc $test.org awk ' /#include <gestimpr.h>/ { print $0 print "#include <userprog.h>" next } /EXEC SQL INCLUDE sqlca.h;/ { print $0 print "EXEC SQL INCLUDE bmtmain.h;" next } /char TcSortie[80];/ { print $0 print "char lib_err1[2000];" next } /EXEC SQL BEGIN DECLARE SECTION;/ { print $0 print "VARCHAR sessionid[21]," print "lib-err[2000]," print "paragraphe_err[80];" print "int cd_ret;" next } { print $0 } ' $file.org > $file done
imprÚvu.wk.sh: 0403-057 Erreur de syntaxe. ligne 3 : `do
Bonjour,
Quel shell utilises-tu ? Est-ce que ce shell comporte une instruction for qui s'écrit comme tu le fais ?
Par ailleurs, tu as un problème au début de ton script :
Ta variable n'est pas $test.pc, mais $fileCode:
1
2
3 for file in test.pc do cp $test.pc $test.org
En fait j'ai repris tout le code
Je le réexecute mais j'ai toujours la même erreurCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 for file in test.pc do cp $file $file.org awk ' /#include <gestimpr.h>/ { print $0 getline if ($0 != "#include <userprog.h>") { print "#include <userprog.h>" } print $0 next } /EXEC SQL INCLUDE sqlca.h;/ { print $0 getline if ($0 != "EXEC SQL INCLUDE bmtmain.h;") { print "EXEC SQL INCLUDE bmtmain.h;" } print $0 next } { print $0 } ' $file.org > $file done
Et j'utilise KSH
Rajoute
au début de ton script et relance le.Code:
1
2#!/bin/ksh
J'ai rajouté la ligne au début de mon script comme tu me l'as soumis, le programme fonctionne, mais il me rajoute #include <userprog.h> après chaque ligne. En plus j'ai toujours ^M qui s'affiche en début et à la fin de chaque ligne du programme.
Là je sais plus quoi faire.
Il y a beaucoup de choses inutiles ou en double dans ce que tu as testé.
Essaye ça, ce qui est sensiblement la même chose que ce que je t'ai déjà proposé:
Pour ce qui concerne les ^M, le problème est ailleurs.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 for file in test.pc do cp $file $file.org awk ' /#include <gestimpr.h>/ { print $0 print "#include <userprog.h>" next } /EXEC SQL INCLUDE sqlca.h;/ { print $0 print "EXEC SQL INCLUDE bmtmain.h;" next } { print $0 } ' $file.org > $file done
les ^M signifient que ton script est au format DOS au lieu du format UNIX.
C'est sans doute la raison des "syntax error" :mouarf:
Solutions pour éliminer les ^M :
ouCode:dos2unix nom_de_fichier
Code:
1
2 tr -d '\r' < nom_de_fichier > tmp mv tmp nom_de_fichier
Merci les gars, ça fonctionne.
Le truc c'est que j'ai pas trop compris la résolution de ^M
Je retravaille dessus
Les fichiers originaux viennent-ils d'une machine sous Windows ? Si oui, comment les transfères-tu ?
Pour régler le problème, tu peux inclure le tr au script:
Remplace la ligne:
} ' $file.org > $file
par
} ' $file.org | tr -d '\r' > $file
Je rédige mes scripts avec notepad++ et je les transfert par FTP avec Filezilla.
Merci mille fois, car tout est rentré dans l'ordre. Le fait d'insérer la modif de ton dernier message m'a enlevé tous les ^M.
J'ai fait évoluer mon script avec d'autres modif, et ça tourne très bien. J'ai mes insertions là où il faut et plus de ^M.
Merci encore