Come sostituire un codice multilinea con sed?


9

Ho un file di grandi dimensioni che contiene caratteri speciali. C'è un codice a più righe lì, che voglio sostituire sed.

Questo:

  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"

Deve trasformarsi in questo:

text = ""

Ho provato il seguente codice, ma senza fortuna:

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

Non sostituisce nulla e non visualizza alcun messaggio di errore

Ci ho giocato, ma tutto ciò che provo non funziona.


Deve essere sedo sei aperto ad altri strumenti? Può esserci "dentro il text=blocco? Possono esserci altri casi text = nel tuo file? Ci saranno sempre 4 righe di testo o ci sarà più / meno?
terdon

Preferibilmente sed, o tutto ciò che non richiede installazione in un server CentOS. Strumenti
pronti all'uso

@terdon Non ce ne sono altri text = nella cartella, l'uscita deve essere text = "". I file hanno 891 righe di codice. Quindi, ha bisogno di rispettare l'altro testo.
blade19899,

vuoi sovrascrivere il file o semplicemente modificare l'output?
JoH1,

@Moonstroke NO OVERWRITE. Deve solo sostituire il testo - come visto nella mia domanda - a text = "". Come visto nella mia domanda.
blade19899,

Risposte:


15

Perl in soccorso:

perl -i~ -0777 -pe 's/text = "[^"]+"/text = ""/g' input-file
  • -i~ modificherà il file "sul posto", lasciando una copia di backup
  • -0777 legge l'intero file in una sola volta, non riga per riga

La sostituzione s///funziona in modo simile come in sed (ovvero corrisponde a text = "seguite da tutte le virgolette diverse volte fino a una virgoletta doppia), ma in questo caso funziona su tutto il file.


5

Devi controllare lo spazio del motivo e continuare a tirare la Nlinea ext se non corrisponde ad es

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

con gnu sedte puoi scriverlo come

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

Non è molto efficiente, meglio selezionare semplicemente l'intervallo /text = "/,/"/, modificare la prima riga ed eliminare il resto:

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)

di nuovo, con gnu sedte puoi scriverlo come una riga:

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

3

Personalmente, lo farei in Perl. Se possiamo supporre che non ci siano "prima della chiusura ", puoi fare:

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

Lo -0slurpe l'intero file, leggendolo in memoria. Il -pmezzo "stampa ogni riga (qui, una" riga "sarà l'intero file) dopo aver applicato lo script fornito da -e". Lo script stesso è un semplice operatore di sostituzione. Catturerà la stringa textseguita da 0 o più caratteri di spazi bianchi, =e di nuovo 0 e più di spazi bianchi ( text\s*=\s*) e la salverà come $1. Quindi sostituirà il modello acquisito e la stringa tra virgolette più corta che trova con il modello ( $1) e "". La sbandiera fa .corrispondere le nuove righe.


correzione, -00legge nei paragrafi, non l'intero file ( rif ). Se il testo tra virgolette contiene una riga vuota, la regex non corrisponderà.
Glenn Jackman,

@glennjackman argh! Ho sempre confuso quelli. . Questo è il motivo per cui ho effettivamente ricontrollato aggiungendo un paragrafo in più ed eseguendo perl -00ne 'print;exit'. E ho ancora messo quello sbagliato nella mia risposta! Grazie, risolto ora.
terdon
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.