Comment remplacer un code multi-lignes par sed?


9

J'ai un gros fichier qui contient des caractères spéciaux. Il y a là un code multi-lignes que je veux remplacer sed.

Cette:

  text = "\
    ------                                                           ------\n\n\
    This message was automatically generated by email software\n\
    The delivery of your message has not been affected.\n\n\
    ------                                                           ------\n\n"

Doit se transformer en ceci:

text = ""

J'ai essayé le code suivant, mais pas de chance:

sed -i '/  text = "*/ {N; s/  text = .*affected.\./  text = ""/g}' /etc/exim.conf

Il ne remplace rien et n'affiche aucun message d'erreur

J'ai joué avec, mais tout ce que j'essaye ne fonctionne pas.


Doit-il l'être sedou êtes-vous ouvert à d'autres outils? Peut-il y avoir "à l'intérieur du text=bloc? Peut-il y avoir d'autres cas text = dans votre dossier? Y aura-t-il toujours 4 lignes de texte ou peut-il y en avoir plus / moins?
terdon

De préférence sed, ou tout ce qui ne nécessite pas d'installation sur un serveur CentOS. Out of the box tools
blade19899

@terdon Il n'y en a pas d'autre text = dans le dossier, le résultat doit être text = "". Les fichiers ont 891 lignes de code. AINSI, il faut respecter l'autre texte.
blade19899

voulez-vous écraser le fichier ou simplement modifier la sortie?
joH1

@Moonstroke AUCUN ÉCRASEMENT. Il suffit de remplacer le texte - comme je l'ai vu dans ma question - par text = "". Comme vu dans ma question.
blade19899

Réponses:


15

Perl à la rescousse:

perl -i~ -0777 -pe 's/text = "[^"]+"/text = ""/g' input-file
  • -i~ éditera le fichier "en place", laissant une copie de sauvegarde
  • -0777 lit tout le fichier en une seule fois, pas ligne par ligne

La substitution s///fonctionne de la même manière que dans sed (c'est-à-dire qu'elle correspond text = "suivie par autre chose que des guillemets doubles plusieurs fois jusqu'à un guillemet double), mais dans ce cas, elle fonctionne sur l'ensemble du fichier.


5

Vous devez vérifier l'espace de motif et continuer à tirer sur la Nligne ext si elle ne correspond pas, par exemple

sed '/text = "/{              # if line matches text = "
:b                            # label b
$!N                           # pull in the next line (if not the last one)
/"$/!bb                       # if pattern space doesn't end with " go to label b
s/".*"/""/                    # else remove everything between the quotes
}' infile

avec gnu sedvous pouvez l'écrire comme

sed '/text = "/{:b;$!N;/"$/!bb;s/".*"/""/}' infile

Ce n'est pas très efficace cependant, mieux vaut simplement sélectionner la plage /text = "/,/"/, modifier la première ligne et supprimer le reste:

sed '/text = "/,/"/{            # in this range
/text = "/!d                    # delete all lines not matching text = "
s/\\/"/                         # replace the backslash with quotes (this is only
}' infile                       # executed if the previous d wasn't executed)

encore une fois, avec gnu sedvous pouvez l'écrire comme une ligne:

sed '/text = "/,/"/{/text = "/!d;s/\\/"/}' infile

3

Personnellement, je le ferais en Perl. Si nous pouvons supposer qu'il n'y en a pas "avant la clôture ", vous pouvez faire:

perl -0pe 's/(text\s*=\s*)".*?"/$1""/s' file

Le -0slurps le fichier entier, le lisant dans la mémoire. Le -pmoyen "imprimer chaque ligne (ici, une" ligne "sera le fichier entier) après avoir appliqué le script donné par -e". Le script lui-même est un simple opérateur de substitution. Il capturera la chaîne textsuivie de 0 ou plusieurs caractères d'espacement, un =et 0 ou plusieurs espaces à nouveau ( text\s*=\s*) et l'enregistrera sous $1. Ensuite, il remplacera le modèle capturé ainsi que la chaîne entre guillemets la plus courte qu'il trouve avec les modèles ( $1) et "". Le sdrapeau fait .correspondre les nouvelles lignes.


correction, -00lit en paragraphes, pas tout le dossier ( réf ). Si le texte entre guillemets contient une ligne vierge, alors l'expression régulière ne correspondra pas.
glenn jackman

@glennjackman argh! Je les mélange toujours. . C'est pourquoi j'ai revérifié en ajoutant un paragraphe supplémentaire et en exécutant perl -00ne 'print;exit'. Et je mets toujours le mauvais dans ma réponse! Merci, réparé maintenant.
terdon
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.