Remplacer la chaîne multiligne dans les fichiers

17

J'ai un certain nombre de fichiers que je souhaite mettre à jour en remplaçant une chaîne multi-lignes par une autre chaîne multi-lignes. Quelque chose dans le sens de:

* Some text, 
* something else
* another thing

Et je veux le remplacer par:

* This is completely
* different text

Le résultat serait qu'après le remplacement, le fichier contenant le premier bloc de texte contiendra désormais la deuxième chaîne (le reste du fichier est inchangé).

Une partie du problème est que je dois trouver la liste des fichiers à mettre à jour dans le système de fichiers. Je suppose que je peux utiliser grep pour cela (bien que ce ne soit pas aussi facile à faire avec des chaînes multilignes) que le canaliser dans sed peut-être?

Y a-t-il un moyen facile de faire ceci? Sed est une option mais c'est gênant car je dois ajouter \ n etc. Existe-t-il un moyen de dire "prenez l'entrée de ce fichier, faites-la correspondre dans ces fichiers, puis remplacez-la par le contenu de cet autre fichier"? Je peux utiliser python si besoin est, mais je veux quelque chose de simple et rapide, donc s'il y a un utilitaire disponible, je préfère l'utiliser plutôt que d'écrire mon propre script (que je sais faire).

ventsyv
la source
Vous devriez probablement utiliser perl pour cela. stackoverflow.com/questions/1030787/…
orion
3
Vous voulez donc faire correspondre some text, something else another things'il s'étend sur plusieurs lignes ou non? Ou vous voulez seulement correspondre some text,\nsomething else\nanotherthing?
mikeserv
2
Modifiez votre question et clarifiez le contenu exact de chaque fichier et la sortie souhaitée.
jimmij
La chaîne s'étend sur plusieurs lignes. Je néglige plutôt les espaces lors de l'appariement / remplacement car ce n'est peut-être pas tout à fait la même chose, mais ce n'est pas grave si je fais juste un match 1-1 (nouvelles lignes et tout).
ventsyv

Réponses:

12

Remplacer "Some ... \ n ... Thing" par le contenu du fichier "new" dans un ou plusieurs fichiers d'entrée

perl -i -p0e 's/Some.*?thing\n/`cat new`/se' input.txt ...
  1. -i changer directement input.txt
  2. -p0 slurp fichier d'entrée et l'imprimer à la fin
  3. s/regexp/.../s dans regexp .est.|\n
  4. s/.../exp/e remplacer par eval(exp)
  5. nouveau - un fichier contenant le texte de remplacement (Ceci est complètement ... un texte différent)
  6. si utile, vous pouvez développer le texte d'origine s/Some text\n...\n...thing\n/...
JJoao
la source
Comment puis-je faire de même avec un fichier appelé «avant» pour rechercher le contenu (multiligne) de ce fichier? J'ai essayé mais ça ne marche pas.
Kvothe
@Kvothe, nous avons besoin de plus de détails ... En supposant que "avant" n'a pas de caractères spéciaux, vous pouvez essayerperl -i -p0e ' $b= `cat before`; s/$b/Some thing\n/se' input.txt ...
JJoao
Et en supposant que "avant" contient tous les caractères spéciaux (nouvelles lignes, barres obliques, crochets) à l'exception de "et".
Kvothe
5
sed -e :n -e '$!N;/\n.*\n/!{$!bn
};  s/some text,\n* *something else\n* *another thing/this is completely\
different text/;P;D' <infile

Je crains que vous ayez du mal à trouver une solution qui vous convienne jusqu'à ce que vous élaboriez une description concrète du problème - mais c'est à cela que l'AQ est le mieux adapté, à mon avis. Peut-être que cela vous donnera une idée - il gardera toujours 3 lignes dans l'espace de motif à la fois - avec un lookahead de 2 lignes - tout en glissant vers l'avant dans le fichier d'entrée uniquement une ligne à la fois.

Il devrait être en mesure de faire correspondre votre chaîne, qu'elle s'étende sur plusieurs lignes ou non - jusqu'à trois, c'est-à-dire. Mais il n'y a aucune disposition pour refléter cette disposition dans le remplacement - elle s'étend toujours sur deux lignes telles qu'elles sont écrites.

mikeserv
la source
0

Pas trop fort (car ne pas chech deuxième chaîne mais c'est facile à régler) et peut être n'est pas compilant posix mais très simple:

sed '/^Some text/{:1;/another thing$/!{N;b 1}
     s/.*/this is completely\ndifferent text/g}' input.txt

La première commande ajoute des lignes à partir du texte jusqu'à ce qu'elles rencontrent autre chose, puis la deuxième ligne le change en un autre texte.

REMARQUE La limitation est que certains textes doivent toujours être suivis d' une autre chose .

Costas
la source
Le problème est que la chaîne peut être plus de 2 lignes (jusqu'à une douzaine environ) et peut contenir d'autres éléments qui doivent être échappés, tels que des tabulations, * etc.
ventsyv
@ventsyv Il n'y a aucun problème avec le nombre de lignes ou de séparateurs - le script vérifie uniquement le début et la fin. C'est assez suffisant si la chaîne de démarrage est exceptionnellement peut marquer le texte à modifier . S'il n'y a pas mieux, montrez l'exemple d'entrée pour produire un motif correct.
Costas du