Çok satırlı kodu sed ile nasıl değiştirebilirim?


9

İçinde özel karakterler olan büyük bir dosya var. Orada değiştirmek istediğiniz çok satırlı bir kod var sed.

Bu:

  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"

Buna dönüşmesi gerekiyor:

text = ""

Aşağıdaki kodu denedim, ama şans yok:

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

Hiçbir şeyin yerini almaz ve herhangi bir hata mesajı görüntülemez

Onunla oynuyorum ama denediğim her şey çalışmıyor.


Olması gerekiyor mu sedyoksa başka araçlara açık mısınız? Bloğun "içinde olabilir text=mi? text = Dosyanızda başka durumlar olabilir mi? Her zaman 4 satır metin olacak mı yoksa daha fazla / daha az olabilir mi?
terdon

Tercihen sedveya bir CentOS sunucusuna kurulum gerektirmeyen herhangi bir şey. Kutudan çıkarılmış aletler
blade19899

@terdon Klasörde başka bir şey yok, çıkışın text = olması gerekiyor text = "". Dosyaların 891 satırlık kodu vardır. Yani, diğer metne saygı duymak gerekiyor.
blade19899

dosyanın üzerine yazmak mı yoksa çıktıyı değiştirmek mi istiyorsunuz?
joH1

@Monstroke YOK AŞIRIYOR. Sadece sorumu - sorumda görüldüğü gibi - değiştirmesi gerekiyor text = "". Sorumda görüldüğü gibi.
blade19899

Yanıtlar:


15

Kurtarmaya Perl:

perl -i~ -0777 -pe 's/text = "[^"]+"/text = ""/g' input-file
  • -i~ "yerinde" dosyasını düzenleyerek yedek kopyasını bırakır
  • -0777 tüm dosyayı satır satır değil, aynı anda okur

İkame s///, sed'de olduğu gibi çalışır (yani, text = "çift ​​tırnak içine alındığında, çift tırnak işareti dışında bir şeyle eşleşir ), ancak bu durumda, tüm dosya üzerinde çalışır.


5

Desen boşluğunu kontrol etmeli ve Neşleşmiyorsa dahili çizgiyi çekmeye devam etmelisiniz.

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

ile gnu sedsiz yazabilirsiniz

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

Bu çok verimli değil, sadece aralığı seçmeniz /text = "/,/"/, ilk satırı değiştirmeniz ve geri kalanını silmeniz daha iyi :

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)

yine, gnu sedtek katmanlı olarak yazabilirsiniz:

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

3

Şahsen, bunu Perl'de yapardım. "Kapanıştan önce hayır olmadığını varsayabiliriz ":

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

-0Belleğe okuma, dosyanın tamamını slurps. -pVasıta "tarafından verilen komut uygulandıktan sonra '(olacak tüm dosya çizgisi burada, a) her satırını yazdırmak' -e". Betiğin kendisi basit bir ikame operatörüdür. Dizeyi ve textardından 0 veya daha fazla boşluk karakteri, bir =ve 0 veya daha fazla boşluk ( text\s*=\s*) tekrar yakalar ve olarak kaydeder $1. Daha sonra, yakalanan kalıbın yanı sıra bulduğu en kısa tırnaklı dizgiyi pattern ( $1) ve ile değiştirir "". sBayrak yapan .maç yeni satırlar.


düzeltme, -00paragrafın tamamını okur, tüm dosyayı değil ( ref ). Tırnak içindeki metin boş bir satır içeriyorsa, normal ifade eşleşmez.
glenn jackman

@glennjackman argh! Bunları hep karıştırıyorum. . Bu yüzden aslında fazladan bir paragraf ekleyerek ve çalışarak tekrar kontrol ettim perl -00ne 'print;exit'. Ve hala yanlış olanı cevabımın içine koyuyorum! Teşekkürler, düzeltildi.
terdon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.