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.

blade19899
la source
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.

choroba
la source
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
don_crissti
la source
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.

terdon
la source
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