Yeni satır karakterleri içeren bir dize değiştirme


10

İle bashaşağıdaki olanlar gibi satırlarla bir dosyada kabuğu,

first "line"
<second>line and so on

Ben bir veya daha fazla tekrarlarını değiştirmek istiyorum "line"\n<second>ile other charactersve her defasında edinin:

first other characters line and so on

Her iki gibi özel karakterler içeren bir dize değiştirmek zorunda Yani "ve <bir satır karakteri ile.

Diğer cevaplar arasında arama yaptıktan sonra sed, komutun sağ tarafında (yani, other charactersdize) yeni satırları kabul edebileceğini buldum , ancak solda değil.

Bir yol (daha basit var mı bu bu sonucu elde etmek) sedya grep?


Mac ile mi çalışıyorsun? \ni sormak neden yapmak ewline ifadedir. insanlar nadiren s//\n/GNU ile yapabildiklerini yapıp yapamayacaklarını sorsa da sed, çoğu diğer kişi sedsağ taraftaki bu kaçışı reddedecektir. yine de, \nkaçış herhangi bir POSIX'te solda çalışacak sedve bunları y/c/\n/aynı etkiye sahip olacak gibi portatif olarak çevirebilirsiniz s/c/\n/gve bu yüzden her zaman yararlı değildir.
mikeserv

Yanıtlar:


3

Üç farklı sedkomut:

sed '$!N;s/"[^"]*"\n<[^>]*>/other characters /;P;D'

sed -e :n -e '$!N;s/"[^"]*"\n<[^>]*>/other characters /;tn'

sed -e :n -e '$!N;/"$/{$!bn' -e '};s/"[^"]*"\n<[^>]*>/other characters /g'

Her üçü de temel s///ikame komutunu temel alır:

s/"[^"]*"\n<[^>]*>/other characters /

Ayrıca sed, kenar çizgilerindeki çıkışlarında farklılık gösterme eğilimi gösterdiğinden , son çizgiyi ele alırken de dikkatli olmaya çalışırlar . Bunun anlamı , son olmayan $!her satırla eşleşen bir adresdir .!$

Ayrıca N, \newline karakterini izleyen desen alanına bir sonraki giriş satırını eklemek için ext komutunu kullanırlar . Kalmış olan herkes sedbir süre ing güvenmek öğrenmiş olacak \newline karakteri - tek yol almak için çünkü biri açıkça oraya koymaktır.

Her üçü de harekete geçmeden önce mümkün olduğunca az girdi okumaya çalışırlar - mümkün olan seden kısa sürede davranır ve bunu yapmadan önce tüm girdi dosyasında okuması gerekmez.

Her şeyi yapsalar da N, her üçü de özyineleme yöntemlerinde farklılık gösterir.

İlk Komut

İlk komut çok basit bir N;P;Ddöngü kullanır . Bu üç komut POSIX uyumlu herhangi bir yerleşiktir sedve birbirlerini güzel şekilde tamamlarlar.

  • N- daha önce de belirtildiği gibi, Ndahili bir giriş hattını, eklenen bir \newline sınırlayıcıyı izleyerek desen alanına ekler .
  • P- gibi p; o Pama sadece ilk çıkan yukarı-to - desen alanı rints \newline karakteri. Ve böylece, aşağıdaki giriş / komut verildiğinde:

    • printf %s\\n one two | sed '$!N;P;d'
  • sed Psadece birini çizer . Ancak, ...

  • D- gibi d; o Ddesen alanı eletes ve başka hat-çevrim başlar. Aksine d , desen uzayında Dsadece ilk oluşan \newline'a kadar siler . \nEwline karakterini takip eden desen alanında daha fazlası varsa sed, bir sonraki satır döngüsüne geriye kalanla başlar. Eğer dönceki örnekte bir ile değiştirilmiştir D, örneğin, sedolur Phem Rint birini ve ikisini .

Bu komut sadece hatlar için recurses yok maç s///ubstitution deyimi. Çünkü s///ubstitution kaldırır \nile eklenen ewline N, zaman kalan asla bir şey var mı sed Deletes desen alanı.

PVe / veya Dseçici olarak uygulamak için testler yapılabilir , ancak bu stratejiye daha uygun başka komutlar da vardır. Özyineleme sadece maç üst üste çizgileri işlemek için uygulanan Çünkü bölümünü yedek kuralının, eşleştirme hatlarının birbirini izleyen diziler iki ucunu bir s///ubstitution iyi çalışmaz .:

Bu girdi verildiğinde:

first "line"
<second>"line"
<second>"line"
<second>line and so on

... yazdırıyor ...

first other characters "line"
<second>other characters line and so on

Bununla birlikte,

first "line"
second "line"
<second>line

... gayet iyi.

İkinci Komut

Bu komut üçüncüye çok benzer. Hem istihdam bir :bçiftlik / test etiket (aynı zamanda joeseph R. cevabı gösterilmiştir burada ) buna ve recurse geri belirli koşulları verilmiş.

  • -e :n -e- taşınabilir sedkomut dosyaları :etiket tanımını \newline veya yeni satır içi xecution -edeyimi ile sınırlar.
    • :n- adlı bir etiketi tanımlar n. Bu herhangi bir zamanda bnveya ile döndürülebilir tn.
  • tn- etiket tanımlandığından veya son olarak ests başarılı olarak adlandırıldığından bu yana herhangi bir ikame olursa test komutu belirtilen bir etikete döner (veya hiçbiri sağlanmazsa, geçerli satır döngüsü için komut dosyasından çıkar) .s///t

Bu komutta, eşleşen satırlar için özyineleme gerçekleşir. Eğer sedbaşarılı olan desen değiştirir diğer karakterler , seddönüşlerin :ntekrar etiket ve denemeden. Bir s///yerine sedkoyma gerçekleştirilmezse, desen uzayını otomatik yazdırır ve bir sonraki satır döngüsünü başlatır.

Bu, ardışık dizileri daha iyi ele alma eğilimindedir. Sonuncusu başarısız olduğunda, bu yazdırır:

first other characters other characters other characters line and so on

Üçüncü Komut

Belirtildiği gibi, buradaki mantık sonrakine çok benzer, ancak test daha açıktır.

  • /"$/bn- bu bir sedtest. Çünkü bçiftliğin komutu bu adresin bir fonksiyonudur, sedsadece olacak bnedeniyle çiftlik geri :nbir sonraki \newline eklenmiş ve desen uzay hala ile bitiyor "ikili tırnak.

Mümkün olduğu kadar Nve arasında çok az şey yapılır b- bu şekilde sed, aşağıdaki satırın kuralınızla eşleşemediğinden emin olmak için gerektiği kadar çok hızlı bir şekilde tam olarak toplanabilir. s///Burada istihdam ki ubstitution farklılık gaynı anda tüm gerekli değiştirmeler yapacağız böylece ve - lobal bayrağı. Aynı giriş verildiğinde bu komut sonuncuya aynı şekilde çıkış verir.


Önemsiz soru için özür dilerim, ama anlamı nedir DATAve metin girişini nasıl alırsınız?
BowPark

@BowPark - Bu örnekte <<\DATA\ntext input\nDATA\npişmiş, ancak bu sadece burada belgedesed kabuk tarafından teslim edilen metindir . Veya gibi çalışır . Bu yardımcı olur mu? sed 'script' filenameprocess that writes to stdout | sed 'script'
mikeserv

Evet öyle, teşekkürler! Neden Ddeğiştirilmiş her çizgi olmadan çift? (Gerektiği gibi kullandınız; belki sedçok iyi bilmiyorum )
BowPark

1
@BowPark - ihmal ederken iki katına çıkarsınız Dçünkü Daksi halde Dşimdi gördüğünüz şeyi iki katına çıkardığınız çıktıdan çıkarır. Az önce bir düzenleme yaptım - ve yakında bu konuyu da genişletebilirim.
mikeserv

1
@BowPark - tamam, güncelledim ve seçenekler sağladım. Şimdi okumak / anlamak biraz daha kolay olabilir. Ben de bu konuya açıkça değindim D.
mikeserv

7

Birkaç basit yolu düşünebilirim ama hiçbirini grepiçermez (zaten ikame yapmaz) veya sed.

  1. Perl

    Değiştirmek için , her ortaya çıkmasını "line"\n<second>ile other characters, kullanım:

    $ perl -00pe 's/"line"\n<second>/other characters /g' file
    first other characters line and so on
    

    Veya, birbirini izleyen birden fazla olayı bir "line"\n<second>olarak ele almak ve hepsini tek bir yerine koymak için şunu other characterskullanın:

    perl -00pe 's/(?:"line"\n<second>)+/other characters /g' file
    

    Misal:

    $ cat file
    first "line"
    <second>"line"
    <second>"line"
    <second>line and so on
    $ perl -00pe 's/(?:"line"\n<second>)+/other characters /g' file
    first other characters line and so on
    

    -00"Satır" ile tanımlanmış olduğu anlamına gelir "Paragraf modunda" dosyasını okumak için Perl neden \n\nyerine \nesas olarak, her paragraf bir hat olarak kabul edilmektedir. Bu nedenle oyuncu değişikliği yeni bir satıra eşittir.

  2. awk

    $  awk -v RS="\n\n" -v ORS="" '{
          sub(/"line"\n<second>/,"other characters ", $0)
          print;
        }' file 
    first other characters line and so on
    

    Aynı temel fikir, kayıt ayırıcıyı ( RS) \n\ntüm dosyayı karıştırmak için, daha sonra çıkış kayıt ayırıcısını hiçbir şeye (aksi takdirde ekstra bir yeni satır yazdırılır) ayarlayıp sub()değiştirmeyi yapmak için işlevi kullanırız.


2
@mikeserv? Hangisi? İkincisi, OP'nin "bir veya daha fazla tekrarını değiştirmek" istediklerini söyledi, bu nedenle paragrafı yemek bekledikleri şey olabilir.
terdon

çok iyi bir nokta. Sanırım her seferinde daha fazla odaklandım ve elde ettim, ancak bunun her olay için bir yedek veya her bir olay sırası için bir yedek olması gerektiği açık değil ... @BowPark?
mikeserv

Her olay için bir değiştirme yapılması gerekir.
BowPark

@BowPark Tamam, o zaman ilk perl yaklaşımı veya awk her ikisinin de çalışması gerekir. Size istenen çıktıyı vermiyorlar mı?
terdon

İşe yarıyor, teşekkürler, ama üçüncü satır awkolmalı print;}' file. Perl'den kaçınmam ve tercihen kullanmam gerekiyor sed, yine de iyi alternatifler önerdiniz.
BowPark

6

dosyanın tamamını oku ve genel bir değişiklik yap:

sed -n 'H; ${x; s/"line"\n<second>/other characters /g; p}' <<END
first "line"
<second> line followed by "line"
<second> and last
END
first other characters  line followed by other characters  and last

Evet. İşe yarıyor, ama birden fazla tekrarlamam olursa?
BowPark

Ha, doğru. Sabit
Glenn Jackson

1
Özür nitpick tekrar ama ${cmds}GNU özeldir - diğer birçok seds gerektirecektir \newline veya -earasındaki mola pve }. Parantezleri tamamen - ve taşınabilir olarak - ve hatta \nilk satıra ekstra ewline karakteri eklemekten kaçınabilirsiniz:sed 'H;1h;$!d;x;s/"line"\n<second>/other characters /g'
mikeserv

Test ettim ve taşınabilir değil gibi görünüyor. Çıktının başına fazladan yeni bir satır yazdırır, ancak sonuç GNU'da doğrudur.
BowPark

Baştaki yeni satırı kaldırmak için: sed -n '1{h;n};H; ${x; s/"line"\n<second>/other characters /g; p}'- ancak bu sürdürülemez hale geliyor.
glenn jackman

3

İşte birden fazla ardışık oluşumunuz varsa işe yarayacak glenn cevabının bir varyantı ( sedsadece GNU ile çalışır ):

sed ':x /"line"/N;s/"line"\n<second>/other characters/;/"line"/bx' your_file

Bu :xsadece dallanma için bir etikettir. Temel olarak, bunun yaptığı, ikame işleminden sonra çizgiyi kontrol etmesidir ve hala eşleşiyorsa "line", :xetikete geri döner (işte budur bx) ve arabelleğe başka bir çizgi ekler ve işlemeye başlar.


@mikeserv Lütfen ne demek istediğiniz hakkında net olun. Benim için çalıştı.
Joseph R.

@mikeserv Özür dilerim, neden bahsettiğinizi gerçekten bilmiyorum. Yukarıdaki kod satırını tekrar terminalime kopyaladım ve düzgün çalıştı.
Joseph R.

1
geri çekildi - bu, sedPOSIX olmayan etiket işlemesini, etiket bildirimi için bir sınırlayıcı olarak bir alanı kabul edecek kadar uzağa götüren GNU'da çalışıyor. Yine de, başkalarının sedorada başarısız olacağını ve başarısız olacağını unutmayın N. GNU , son satırda sedbırakmadan önce desen alanı yazdırmak için POSIX yönergelerini ihlal Neder, ancak POSIX, son satırda bir Nkomut okunduğunda hiçbir şeyin yazdırılmaması gerektiğini açıkça belirtir .
mikeserv

Gönderiyi GNU belirtecek şekilde düzenlerseniz oyumu tersine çevirir ve bu yorumları silerim. Ayrıca, GNU'nun vbirbirini kıran sedama GNU sürüm 4 ve daha üstündeki bir işlem olmayan komutunu öğrenmeye değer olabilir .
mikeserv

1
Bu portably gibi yapılabilir - bu durumda ben bir daha sunacak sed -e :x -e '/"line"/{$!N' -e '};s/"line"\n<second>/other characters/;/"line"/bx'.
mikeserv
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.