Bonjour,
Je dois modifier plusieurs programmes sous UNIX (ajouter des lignes après certaines commandes). comment puis-je faire pour automatiser ces modifications ?
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 : Sélectionner tout - Visualiser dans une fenêtre à part 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 : Sélectionner tout - Visualiser dans une fenêtre à part echo "message" >> fichier.txt
pour ajouter la ligne à tous les fichiers du répertoire courant (*).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 fichiers
Code : Sélectionner tout - Visualiser dans une fenêtre à part #include <gestimpr.h>
je veux ajouter après cette ligne
un autre exemple
Code : Sélectionner tout - Visualiser dans une fenêtre à part #include<userprog.h>
J'ai une ligne
et je veux ajouter après cette ligne
Code : Sélectionner tout - Visualiser dans une fenêtre à part EXEC SQL INCLUDE sqlca.h;
et ainsi de suite
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part sed -i 's/#include <gestimpr.h>/&\n#include<userprog.h>/' *.pc
Code : Sélectionner tout - Visualiser dans une fenêtre à part 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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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.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.(à condition encore, d'avoir un shell décent... sinon, il faut passer par un fichier...)
Ca se discute.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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 occupeJe 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 : Sélectionner tout - Visualiser dans une fenêtre à part
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.
Partager