Awk / sed ile birden çok kez oluşabilecek iki işaretçi deseni arasındaki çizgiler nasıl seçilir


119

İki farklı işaretçi deseni arasında oluşan çizgileri kullanarak awkveya sednasıl seçebilirim? Bu desenlerle işaretlenmiş birden çok bölüm olabilir.

Örneğin: Dosyanın şunları içerdiğini varsayalım:

abc
def1
ghi1
jkl1
mno
abc
def2
ghi2
jkl2
mno
pqr
stu

Ve başlangıç ​​modeli abcve bitiş modeli mno Yani, çıktıya şu şekilde ihtiyacım var:

def1
ghi1
jkl1
def2
ghi2
jkl2

Bir kez kalıbı eşleştirmek için sed kullanıyorum:

sed -e '1,/abc/d' -e '/mno/,$d' <FILE>

Dosyanın sonuna kadar tekrar tekrar girmenin sedveya yapmanın bir yolu var mı awk?

Yanıtlar:


188

awkGerektiğinde baskıyı tetiklemek için bir bayrakla kullanın :

$ awk '/abc/{flag=1;next}/mno/{flag=0}flag' file
def1
ghi1
jkl1
def2
ghi2
jkl2

Bu nasıl çalışıyor?

  • /abc/bu metne sahip satırlarla eşleşir /mno/.
  • /abc/{flag=1;next}flagmetnin ne zaman bulunduğunu ayarlar abc. Ardından, satırı atlar.
  • /mno/{flag=0}flagmetnin ne zaman bulunduğunu siler mno.
  • Son flag, varsayılan eyleme sahip bir modeldir, bu şudur print $0: flag1'e eşitse, satır yazdırılır.

Modellerin gösterilip gösterilmediği durumlarla birlikte daha ayrıntılı bir açıklama ve örnekler için, bkz. İki desen arasındaki çizgiler nasıl seçilir? .


30
Desen dahil ve arasındaki her şeyi yazdırmak istiyorsanız kullanabilirsiniz awk '/abc/{a=1}/mno/{print;a=0}a' file.
scai

6
Evet, @scai! veya hatta awk '/abc/{a=1} a; /mno/{a=0}' file- bununla a, /mno/bizden önce koşul koymak , çizgiyi ayarlamadan önce doğru olarak değerlendirir (ve yazdırır) a=0. Bu şekilde yazmaktan kaçınabiliriz print.
fedorqui

12
@scai @fedorqui Desen çıktısını dahil etmek için şunları yapabilirsinizawk '/abc/,/mno/' file
Jotne

1
@hkasera awk '/abc/{flag=1}/mno/{flag=0}flag' fileyapmalı.
fedorqui

2
@EirNym, çok farklı şekillerde ele alınabilen garip bir senaryo: Hangi satırları yazdırmak istersiniz? Muhtemelen awk 'flag; /PAT1/{flag=1; next} /PAT1/{flag=0}' fileyapar.
fedorqui

45

Kullanarak sed:

sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'

-nOpsiyon aracı varsayılan olarak yazdırmaz.

Kalıp, sadece abciçin içeren satırları arar mnove ardından eylemleri { ... }. İlk işlem abcsatırı siler ; ikincisi mnoçizgi; ve pkalan satırları yazdırır. Normal ifadeleri gerektiği gibi gevşetebilirsiniz. abc.. aralığı dışındaki satırlar mnoyazdırılmaz.


Cevabınız ve açıklama için teşekkürler! :)
dvai


1
@KasunSiyambalapitiya: Çoğunlukla kullanmayı sevdiğim anlamına geliyor. Resmi olarak, bir sonraki argümanın sedçalıştırılması gereken komut dosyasının (parçası) olduğunu belirtir . Tüm komut dosyasını dahil etmek için birkaç argüman kullanmak istiyorsanız veya kullanmanız gerekiyorsa, -ebu tür her argümandan önce kullanmanız gerekir ; aksi takdirde isteğe bağlıdır (ancak açık).
Jonathan Leffler


Güzel! (Sed yerine awk kullanmayı tercih ederim.) Karmaşık düzenli ifadeler kullanırken, onları tekrarlamak zorunda kalmamak güzel olurdu. "Seçilen" aralığın ilk / son satırını silmek mümkün değil mi? Ya da önce dilk eşleşmeye kadar tüm satırlara, sonra dda ikinci eşleşmeden başlayarak tüm satırlara başka bir uygulama mı?
hans_meine

18

Bu sizin için işe yarayabilir (GNU sed):

sed '/^abc$/,/^mno$/{//!b};d' file

Başlangıç abcve bitiş satırları arasındakiler dışındaki tüm satırları silmno



Bu harika. Bu {//!b}, abcve mnoçıktıya dahil edilmeyi engeller , ancak nasıl olduğunu anlayamıyorum. Açıklar mısın
Brendan

1
@Brendan komut //!b, mevcut satırın aralıkla eşleşen satırlardan biri olmaması durumunda okur, bu satırları keser ve bu nedenle yazdırır, aksi takdirde diğer tüm satırlar silinir.
2017

13
sed '/^abc$/,/^mno$/!d;//d' file

golf, ppotong'dan iki karakter daha iyi {//!b};d

Boş eğik çizgiler şu //anlama gelir: "kullanılan son düzenli ifadeyi yeniden kullanın". ve komut daha anlaşılır olanla aynı şeyi yapar:

sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file

Bu POSIX gibi görünüyor :

Bir RE boşsa (yani, herhangi bir model belirtilmemişse), uygulanan son komutta (bir adres olarak veya bir ikame komutunun parçası olarak) kullanılan son RE belirtilmiş gibi davranacaktır.


1
İkinci komut da bir aralık olduğu için ikinci çözümün hiçbir şeyle sonuçlanmayacağını düşünüyorum. Ancak ilki için tebrikler.
Potong

@potong true! İlkinin neden işe yaradığını daha fazla araştırmalıyım. Teşekkürler!
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

7

Önceki yanıtın bağlantılarından, kshSolaris üzerinde çalışan benim için bunu yapan şuydu:

sed '1,/firstmatch/d;/secondmatch/,$d'
  • 1,/firstmatch/d: 1. satırdan ilk bulduğunuza kadar firstmatchsilin.
  • /secondmatch/,$d: ilk oluşumundan secondmatchdosyanın sonuna kadar silin.
  • Noktalı virgül, sırayla yürütülen iki komutu ayırır.

Merak ediyorum, neden aralık sınırlayıcı ( 1,) daha önce geliyor /firstmatch/? Sanırım bu da ifade edilebilir '/firstmatch/1,d;/secondmatch,$d'mi?
Luke Davis

2
"1, / firstmatch / d" ile "1. satırdan" ilk karşılaşmayı "bulana kadar sil" diyorsunuz. Oysa "/ secondmatch /, $ d" ile "ikinci eşleşme" nin ilk oluşumundan dosyanın sonuna kadar "sil" diyorsunuz. noktalı virgül, sırayla yürütülen iki komutu ayırır.
FanDeLaU

2
perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file

Hem awk hem de sed için oldukça iyi bir alternatif olduğu için perl eşdeğerini bilmek güzel.
akhan

2

bunun gibi bir şey benim için çalışıyor:

file.awk:

BEGIN {
    record=0
}

/^abc$/ {
    record=1
}

/^mno$/ {
    record=0;
    print "s="s;
    s=""
}

!/^abc|mno$/ {
    if (record==1) {
        s = s"\n"$0
    }   
}

kullanma: awk -f file.awk data...

düzenleme: O_o fedorqui çözümü benimkinden çok daha iyi / güzel.


3
GNU'da awk if (record=1)olmalıdır if (record==1), yani çift = - bkz. Gawk karşılaştırma operatörleri
George Hawkins,

2

Don_crissti'nin yalnızca eşleşen 2 desen arasındaki metni göster ?

firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile

AWK'nın uygulamasından çok daha verimli olan, buraya bakın .


Soruların gereksinimleri, dolayısıyla çözümleri oldukça farklı olduğu için, burada zaman karşılaştırmaları arasında bağlantı kurmanın pek mantıklı olduğunu düşünmüyorum.
fedorqui

2
Katılmıyorum çünkü cevapları karşılaştırmak için bazı kriterlerimiz olmalı. Sadece birkaçında SED uygulaması var.
Léo Léopold Hertz 준영

0

Desen2 aynı zamanda desen1 ile eşleşirkenawk iki desen arasındaki satırları yazdırmayı denedim . Ve pattern1 satırı da yazdırılmalıdır.

örneğin kaynak

package AAA
aaa
bbb
ccc
package BBB
ddd
eee
package CCC
fff
ggg
hhh
iii
package DDD
jjj

bir çıktısı olmalı

package BBB
ddd
eee

Pattern1 olduğunda package BBB, pattern2 olduğunu package \w*. Bunu not etCCC bilinen bir değer olmadığını ve bu nedenle tam anlamıyla eşleştirilemeyeceğini unutmayın.

Bu durumda, ne @scai awk '/abc/{a=1}/mno/{print;a=0}a' filene de @fedorquiawk '/abc/{a=1} a; /mno/{a=0}' file benim için çalışıyor.

Sonunda bunu çözmeyi başardım awk '/package BBB/{flag=1;print;next}/package \w*/{flag=0}flag' file haha

Biraz daha fazla çaba awk '/package BBB/{flag=1;print;next}flag;/package \w*/{flag=0}' file, pattern2 satırını da yazdırmakla sonuçlanır , yani

package BBB
ddd
eee
package CCC
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.