Jak zamienić kod wieloliniowy na sed?


9

Mam duży plik, który zawiera znaki specjalne. Jest tam kod wieloliniowy, który chcę zastąpić sed.

To:

  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"

Musi zmienić się w to:

text = ""

Próbowałem następującego kodu, ale bez powodzenia:

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

Niczego nie zastępuje i nie wyświetla żadnych komunikatów o błędach

Bawiłem się tym, ale wszystko, co próbuję, nie działa.


Czy to musi być sedczy jesteś otwarty na inne narzędzia? Czy może być "w text=bloku? Czy text = w twoim pliku mogą znajdować się inne przypadki ? Czy zawsze będą 4 wiersze tekstu, czy może być więcej / mniej?
terdon

Najlepiej sedlub cokolwiek, co nie wymaga instalacji na serwerze CentOS.
Gotowe

@terdon Nie ma innych text = w folderze, musi być wyjście text = "". Pliki zawierają 891 linii kodu. SO, musi respektować drugi tekst.
blade19899

chcesz zastąpić plik lub po prostu zmodyfikować dane wyjściowe?
joH1

@Moonstroke NO OVERWRITE. Wystarczy zastąpić tekst - jak widać w moim pytaniu - na text = "". Jak widać w moim pytaniu.
blade19899

Odpowiedzi:


15

Perl na ratunek:

perl -i~ -0777 -pe 's/text = "[^"]+"/text = ""/g' input-file
  • -i~ edytuje plik „na miejscu”, pozostawiając kopię zapasową
  • -0777 czyta cały plik na raz, nie wiersz po wierszu

Podstawienie s///działa podobnie jak w sed (tzn. Dopasowuje, text = "po którym następuje wielokrotność cudzysłowu wiele razy aż do podwójnego cudzysłowu), ale w tym przypadku działa na całym pliku.


5

Musisz sprawdzić przestrzeń wzoru i ciągnąć Nlinię zewnętrzną, jeśli nie pasuje ona np

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

z gnu sedmożesz napisać to jako

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

Nie jest to jednak zbyt wydajne, lepiej po prostu wybierz zakres /text = "/,/"/, zmodyfikuj pierwszy wiersz i usuń resztę:

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)

jeszcze raz, gnu sedmożesz napisać to jako jedno-linijkę:

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

3

Osobiście zrobiłbym to w Perlu. Jeśli możemy założyć, że nie ma "przed zamknięciem ", możesz zrobić:

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

-0Slurps całego pliku, czytając ją w pamięci. Te -pśrodki „wydrukować każdą linię (tutaj jest«linia»będzie cały plik) po zastosowaniu skryptu podane przez -e”. Sam skrypt jest prostym operatorem podstawiania. Przechwyci ciąg, textpo którym następuje 0 lub więcej białych znaków, =i ponownie 0 i więcej białych znaków ( text\s*=\s*) i zapisze go jako $1. Następnie zastąpi przechwycony wzorzec, a także najkrótszy cytowany ciąg znaleziony wzorcem ( $1) i "". sFlag sprawia .newlines meczu.


korekta, -00czyta w punktach, a nie cały plik ( ref ). Jeśli tekst w cudzysłowie zawiera pusty wiersz, wyrażenie regularne nie będzie pasować.
glenn jackman

@glennjackman argh! Zawsze się mylę. . Dlatego właśnie dwukrotnie sprawdziłem, dodając dodatkowy akapit i uruchamiając perl -00ne 'print;exit'. I wciąż podaję niewłaściwy w swojej odpowiedzi! Dzięki, naprawione teraz.
terdon
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.