Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 08/06/2017, à 06:56

PowaBanga

remplacer du texte en masse dans 150 fichiers

salut à tous,
je dois ici remplacer du texte dans près de 150 fichier, mais ça me semble très compliqué à faire, du coup, j'ai pensé qu'il serait peut-etre possible de le faire via le terminal.

J'ai donc trouvé ceci ;

echo htmlentities/highlight_string/g' *.php

ici pour modifier "echo htmlentities" par "highlight_string" dans tous les fichiers php.

Mais mon souci est beaucoup plus complexe que cela. C'est à dire que mes fhichier contient ceci :

{
"origin" "-896 1216 60"
"points" "0"
"kills" "50"
"count" "2"
"dll" "grm"
"message" "Axis"
"obj_owner" "1"
"classname" "info_team_start"
}
{
"origin" "-624 -944 38"
"points" "0"
"kills" "50"
"count" "2"
"dll" "usm"
"message" "Allies"
"classname" "info_team_start"
}

Donc, je souhaite modifier le numéro du kill de l'un à 150 et de l'autre  à 30. Sachant que le nombre de kills peut varier d'un fichier à l'autre, la seule chose en commun sont se sont les premiers mots entre apostrophe.

Mon point de repère pour savoir à quel équiper je veux attribuer des kill sont les variable des dll.

Donc par exemple dans tous les fichiers, les accolade qui contiennent la variable "dll usm" ou "usa" aurai un kill de 30 et tous ceux de grm ou ita, auraient un kill de 150.

J'espère m'être exprimer assez clairement, je ne sais pas du tout comment m'y prendre avec ça, si quelqu'un sait m'aider, ça serait vraiment super top smile

Hors ligne

#2 Le 08/06/2017, à 07:49

pingouinux

Re : remplacer du texte en masse dans 150 fichiers

Bonjour,
La première commande que tu montres n'a pas de sens; il doit manquer le début.

Si j'ai bien compris, et si l'ordre des champs entre les accolades est toujours le même, tu peux essayer le script python mon_script.py. Il ne touche pas aux fichiers d'origine, mais crée un fichier modifié mon_fichier.php_ pour chaque mon_fichier.php.

#!/usr/bin/env python
import sys, re, glob
 
fichiers=sys.argv[1:]
rec_acco=re.compile('({[^{}]*})') # Recherche du texte entre accolades
 
for fic in fichiers:
   with open(fic,'r') as f: s=f.read()
   with open(fic+'_','w') as g:
      while True :
         k=rec_acco.search(s)
         if(k) :
            acco=k.group(1)
            champs=acco.split('\n'); modif=False
            if champs[5]=='"dll" "usm"' or champs[5]=='"dll" "usa"' :
               champs[3]='"kills" "30"'; modif=True
            if champs[5]=='"dll" "grm"' or champs[5]=='"dll" "ita"' :
               champs[3]='"kills" "150"'; modif=True
            if modif: acco='\n'.join(champs)
            g.write(s[:k.start(1)])
            g.write(acco)
            s=s[k.end(1):]
         else :
            g.write(s)
            break

À appeler ainsi, après l'avoir rendu exécutable :

./mon_script.py *.php

Tu peux d'abord le tester sur un seul fichier :

./mon_script.py mon_fichier_test.php

Hors ligne

#3 Le 08/06/2017, à 11:35

gigiair

Re : remplacer du texte en masse dans 150 fichiers

Emacs permet d'effectuer une recherche et remplacement sur un ensemble de fichiers sélectionnés.
https://www.gnu.org/software/emacs/manu … files.html

Ça marche comme n'importe quelle recherche et remplacement dans un éditeur de texte.
Par exemple

M-x find-name-dired RET ~/Chemin/vers/répertoire  RET *.php RET t Q echo htmlentities RET highlight_string RET !

fait la recherche et remplacement dans tous les fichiers *.php de l'arborescence

M-x signifie que l'on doit taper la touche Meta (Alt sur PC) et la touche x simultanément, RET représente la touche retour chariot (^M).
Il est possible d'avoir une sélection plus subtile en utilisant la commande find-dired avec toutes les options de la commande find, et la recherche-remplacement utilise des regexp.
la commande ! à la fin valide tous les remplacement sans confirmation individuelle. Elle est facultative, sans ça les validations doivent se faire une à une.

Dernière modification par gigiair (Le 08/06/2017, à 14:13)


--
JJR.

Hors ligne

#4 Le 08/06/2017, à 14:47

PowaBanga

Re : remplacer du texte en masse dans 150 fichiers

pingouinux merci beaucoup pour ton script, malheureusement les fichiers ne sont pas toujours les même et les lignes pas toujours dans le même ordre. Mais ton script me servira ultérieurement c'est sûr ! smile

gigiair,ici, je dois donc attribuer une valeur différente à deux variable "kill" en fonction de la dll utilisée. Quand je lis ta commande, j'ai l'impression que ca va remplacer tous les kill par la même valeur... du coup, je ne comprend pas très bien comment utiliser la commande find-dired pour faire cela... ? hmm

Hors ligne

#5 Le 08/06/2017, à 14:49

pingouinux

Re : remplacer du texte en masse dans 150 fichiers

Dans ce cas, montre un exemple de fichier réaliste, et le résultat que tu veux.

Hors ligne

#6 Le 08/06/2017, à 14:55

PowaBanga

Re : remplacer du texte en masse dans 150 fichiers

je ne suis pas sur de comprendre ta question, tu semble pourtant avoir parfaitement bien compris ce que je voulais dans ton précédent message,

J'ai par exemple dans un autre fichier :

{
"nextmap" "polmunf3b"
"kills" "65"
"count" "99"
"dll" "grm"
"obj_owner" "1"
"message" "Axis"
"origin" "-469.2 140 354.3"
"classname" "info_team_start"
}
{
"nextmap" "polmunf3b"
"kills" "65"
"count" "99"
"dll" "pol"
"obj_owner" "0"
"message" "Polish"
"origin" "971.5 -152.3 -180.7"
"classname" "info_team_start"
}

Il y donc des centaines d'autres ligne de texte à ne pas modifier,

et  à la fin, je voudrais que la valeur de tous les kill de tel et tel dll soient  à 30, et que tous ceux de tel et tel dll soient à 150 par exemple

{
"nextmap" "polmunf3b"
"kills" "30"
"count" "99"
"dll" "grm"
"obj_owner" "1"
"message" "Axis"
"origin" "-469.2 140 354.3"
"classname" "info_team_start"
}
{
"nextmap" "polmunf3b"
"kills" "150"
"count" "99"
"dll" "pol"
"obj_owner" "0"
"message" "Polish"
"origin" "971.5 -152.3 -180.7"
"classname" "info_team_start"
}

Hors ligne

#7 Le 08/06/2017, à 16:25

gigiair

Re : remplacer du texte en masse dans 150 fichiers

PowaBanga a écrit :

gigiair,ici, je dois donc attribuer une valeur différente à deux variable "kill" en fonction de la dll utilisée. Quand je lis ta commande, j'ai l'impression que ca va remplacer tous les kill par la même valeur... du coup, je ne comprend pas très bien comment utiliser la commande find-dired pour faire cela... ? hmm

Ce n'est pas la fonction find-dired qui effectue le remplacement. find-dired ne sert que pour la sélection des fichiers (qu'on peut aussi effecuter « à la main ».
Le remplacement est effectuée par la commande query-replace-regexp et la partie à remplacée est sélectionnée par une regexp et peut tout à fait s'adapter au contexte et effectuer des remplacements qui en dépendent. On peut insérer dans la chaîne de remplacement du code elisp qui est tout aussi complet et puissant que le code python. Ta requête ne pose aucun problème pour être exécutée par cette commande, c'est fait pour.
Je suis désolé, mais je ne comprend pas très clairement ton désir, sinon je te proposerais un exemple.


--
JJR.

Hors ligne

#8 Le 08/06/2017, à 18:00

pingouinux

Re : remplacer du texte en masse dans 150 fichiers

PowaBanga #1 a écrit :

Donc par exemple dans tous les fichiers, les accolade qui contiennent la variable "dll usm" ou "usa" aurai un kill de 30 et tous ceux de grm ou ita, auraient un kill de 150.

Ton fichier de sortie en #6 n'est pas, à mon avis, compatible avec ta demande en #1.

Voici un script qui ne suppose pas un ordre des champs identique dans tous les fichiers :

#!/usr/bin/env python
import sys, re, glob

fichiers=sys.argv[1:]
rec_acco=re.compile('({[^{}]*})') # Recherche du texte entre accolades

for fic in fichiers:
   with open(fic,'r') as f: s=f.read()
   with open(fic+'_','w') as g:
      while True :
         k=rec_acco.search(s)
         if(k) :
            modif=False
            acco=k.group(1)
            champs=acco.split('\n')
            for champ in champs:
               try: cle,val=champ.split()
               except ValueError: cle=champ
               if cle=='"dll"':
                  if   val=='"usm"' or val=='"dll"': kil='"30"'; modif=True
                  elif val=='"grm"' or val=='"ita"': kil='"150"'; modif=True
                  break
            if modif:
               new_champs=[]
               for champ in champs:
                  try: cle,val=champ.split()
                  except ValueError: cle=champ
                  if cle=='"kills"': new_champ=' '.join((cle,kil))
                  else:              new_champ=champ
                  new_champs.append(new_champ)
               champs=new_champs
            acco='\n'.join(champs)
            g.write(s[:k.start(1)])
            g.write(acco)
            s=s[k.end(1):]
         else :
            g.write(s)
            break

Hors ligne

#9 Le 08/06/2017, à 19:57

Watael

Re : remplacer du texte en masse dans 150 fichiers

oh, la vache, le python, ça donne le vertige.

sed -rn '/\{/{
   :a;
   /\}/!{ N;ba; };
   /"dll" "grm"/s/"kills" "[^"]/"kills" "150/;
   /"dll" "usm"/s/"kills" "[^#]/"kills" "30/;
   p;
}' *.php

c'est du bricolage, c'est largement perfectible.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#10 Le 09/06/2017, à 18:13

PowaBanga

Re : remplacer du texte en masse dans 150 fichiers

Alors, le scipt en python, je l'ai mis dans le dossier avec mes fichiers, en le lançant dans un terminal, cela remplace mon curseur par une croix,  avec la quelle je peut encadre plusieurs fichiers.
mais cela me renvois l'erreur suivante :

/home/PowaBanga/.yq2/dday/mode/alliedhero/aaa: ligne 6: erreur de syntaxe près du symbole inattendu « ( »
/home/PowaBanga/.yq2/dday/mode/alliedhero/aaa: ligne 6: `rec_acco=re.compile('({[^{}]*})') # Recherche du texte entre accolades'

Le script sed lui, j'ai rencontré deux souci avec :
le premier est que dans le texte du terminal, il a remplacé la valeur de mes kills pas 1500 et 300 au lieu de 150 et 30, ça fais vachement beaucoup de kills du coups ^^
le second, et que mon fichier ne s'est pas modifié, quand je l'ouvre avec kwrite, mes kill sont toujours à 60 et 60

Peut-être cela en il en lien avec ce message que kwrite me met en ouvrant mes fichiers :

Le fichier /home/PowaBanga/.yq2/dday/mode/alliedhero/ambush_b3.ent a été ouvert avec un encodage UTF-8 mais contient des caractères non autorisés.
Il est en mode lecture seule car l'enregistrer risquerait d'endommager son contenu.
Veuillez soit ré-ouvrir le fichier avec l'encodage correct choisi, soit activer le mode lecture-écriture à nouveau dans le menu Outils pour pouvoir modifier ce fichier.

Hors ligne

#11 Le 09/06/2017, à 19:44

Watael

Re : remplacer du texte en masse dans 150 fichiers

par défaut, sed ne modifie pas le fichier d'origine.
pour cela, il faut ajouter l'option -i.

et, étant donné que tu en as plusieurs, il serait bon d'ajouter l'option -s pour différencier les fichiers.

Dernière modification par Watael (Le 09/06/2017, à 19:45)


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#12 Le 09/06/2017, à 20:08

PowaBanga

Re : remplacer du texte en masse dans 150 fichiers

ha, voilà qui fonction à perfection, mais il y a quand même un zero de trop à chaque fois ! sad
comment cela se fait ?
En fait je viens de retester, et il rajoute un zero à chaque fois que je lance le script, ou bien alors il ne supprime pas le dernier zero...

Hors ligne

#13 Le 09/06/2017, à 20:47

Watael

Re : remplacer du texte en masse dans 150 fichiers

ah, la, la, j'ai oublié un morceau de la syntaxe hmm

sed -rn '/\{/{
   :a;
   /\}/!{ N;ba; };
   /"dll" "grm"/s/"kills" "[^"]*"/"kills" "150"/;
   /"dll" "usm"/s/"kills" "[^"]*"/"kills" "30"/;
   p;
}'

teste, et ajoute les options indiquées précédemment.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#14 Le 09/06/2017, à 21:21

PowaBanga

Re : remplacer du texte en masse dans 150 fichiers

Ho génial, comme ça claque yikes
hé dis, penses-tu qu'il soit possible par exemple, de modifier le nombre de kills par 2 ?
Par exemple : l'un est à 50, l'autre est à  40, et qu'ils deviennent 25 et 20 ...

Hors ligne