Belirli bir dize ve aşağıdaki satırı içeren satırı kaldır


70

Bunu kullanıyorum

cat foo.txt | sed '/bar/d'

barDosyadaki dizeyi içeren satırları kaldırmak için.

Bununla birlikte, bu satırları ve hemen ardından gelen satırları kaldırmak istiyorum . Tercihen de sed, awkmingw32 olarak kullanılabilir veya diğer bir araç.

Ben de alabilirim ne ters bir tür grepolan -Ave -Beşleştirilmiş satırdan sonra / önce eşleşen satırları yanı sıra çizgileri yazdırmak için.

Bunu başarmanın kolay bir yolu var mı?


2
Sadece bilgi almak için: Girişlerin iki gömlek olduğu günlükleri analiz ediyorum. Bu yüzden, kalıpla eşleşen bir giriş bulmak ve sonraki satırın yanı sıra kaldırmak istiyorum. Dolayısıyla ardışık eşleşme çizgileriyle uğraşmama gerek yok ama yine de cevaplarınızın eksiksizliği için teşekkürler!
jakub.g

Yanıtlar:


74

GNU sed'iniz varsa (yani gömülü olmayan Linux veya Cygwin):

sed '/bar/,+1 d'

Eğer varsa bariki ardışık hatlarında, bunu analiz etmeden ikinci çizgiyi siler. Örneğin, 3 satırlı bir dosyanız bar/ bar/ varsa foo, foosatır kalacak.


1
Uzunluk için +1 :) Özel örneğimde ardışık s'lerim yok, barbu yüzden bunu hatırlamak çok kolay.
jakub.g

11
sed '/bar/d'Sadece bir sonraki değil "belirli bir dize içeren satırı kaldır" yapmak istiyorsanız .
AJP,

Eğer matematikten sonra tüm satırları kaldırmak istersem?
Pandya

1
@Pandya Bu farklı. Örneğin kullanabilirsinizsed '/math/q'
Gilles

1
@AK Sadece eşleşen satırı silmek istiyorsanız, daha da basitleşir:sed '/bar/d'
Gilles

16

Eğer barardışık hatlarda oluşabilecek, bunu yapabilirsiniz:

awk '/bar/{n=2}; n {n--; next}; 1' < infile > outfile

bu, yukarıdaki 2'yi silmek için, eşleşen 2'yi de içeren silinecek satır sayısı ile değiştirmek suretiyle uyarlanabilir.

Değilse, @ MichaelRollins'in çözümüsed ile kolayca yapılabilir :

sed '/bar/,/^/d' < infile > outfile

AWK çözeltide diğer artı yerini alabilir olmasıdır /bar/ile /bar|baz|whatever/. Bu sedsözdiziminde işe görünmüyor.
jakub.g

@ jakub.g, GNU sed'im var (şimdi v4.4). Diğerlerinden emin değilim. Bildiğim şey, varsayılan olarak "temel" normal ifade sözdizimini kullandığı ve bu nedenle örneğinizin işe yaramadığı. İstediğinizi elde etmek için her dikey çizginin önüne ters eğik çizgi koyabilir veya sed"genişletilmiş" normal ifadeler kullanabilirsiniz. Daha fazla bilgi burada: gnu.org/software/sed/manual/html_node/… . Lütfen bunun için de geçerli olduğunu unutmayın grep. İşte benim kendi çalışma örnek: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'.
Victor Yarema

12

Ben sed içinde akıcı değilim, ama bunu awk olarak yapmak kolaydır:

awk '/bar/{getline;next} 1' foo.txt 

Awk betiği okur: çubuk içeren bir satır için sonraki satırı (getline) alın, ardından sonraki tüm işlemleri (sonraki) atlayın. Sondaki 1 desen kalan satırları yazdırır.

Güncelleme

Yorumda belirtildiği gibi, yukarıdaki çözüm ardışık olarak işe yaramadı bar. İşte göz önünde bulundurulan ve gözden geçirilmiş bir çözüm:

awk '/bar/ {while (/bar/ && getline>0) ; next} 1' foo.txt 

Şimdi tüm / bar / satırlarını atlamak için okumaya devam ediyoruz.


1
grep -A% 100 kopyalamak için , aynı anda arka arkaya bardoğru herhangi bir sayıda satırı da işlemeniz gerekir (tüm bloğu kaldırarak ve sonra 1 satırı).
jw013

7

Bunu başarmak için sed'in komut dosyası yeteneklerinden yararlanmak isteyeceksiniz.

$ sed -e '/bar/ { 
 $!N
 d
 }' sample1.txt

Örnek veri:

$ cat sample1.txt 
foo
bar
biz
baz
buz

"N" komutu bir sonraki giriş satırını desen alanına ekler. Bu, desen eşleşmesinden (/ bar /) gelen çizgiyle birleştirildiğinde silmek istediğiniz çizgiler olacaktır. Daha sonra "d" komutu ile normal şekilde silebilirsiniz.


Konsolda nasıl newline yazabilirim? Yoksa bu sadece script mi?
jakub.g

@ jakub.g: GNU sed ile:sed -e '/bar/{N;d}' sample1.txt
Cyrus

2

Bir eşleşmeyi izleyen herhangi bir satırın hemen kaldırılması gerekiyorsa, sedprogramınız ardışık eşleşmeleri dikkate almalıdır . Başka bir deyişle, aynı zamanda eşleşen bir eşleşmeyi izleyen bir çizgiyi kaldırırsanız, o zaman muhtemelen onu izleyen çizgiyi de kaldırmalısınız.

Basitçe yeterli bir şekilde uygulanır - ancak biraz geriye bakmanız gerekir.

printf %s\\n     0 match 2 match match \
                 5 6 match match match \
                 10 11 12 match 14 15  |
sed -ne'x;/match/!{g;//!p;}'

0
6
11
12
15

Okunan her satır için tutma ve desen boşluklarını değiştirerek çalışır - böylece son satır her zaman akıma göre karşılaştırılabilir. Bu nedenle, sedbir satır okuduğunda, arabelleklerinin içeriğini değiştirir - ve önceki satır, düzenleme satırının içeriğidir, mevcut satır boşluğa yerleştirilir.

Yani sedbir maç için önceki hattını kontrol eder matchve eğer onun !iki ifadeler bulunmayan {işlevi }çalıştırılır. sedolacak gve model alanı üzerine yazarak tutma alanı - bu olacaktır - ve daha sonra mevcut hat tutma ve desen boşluk hem de daha sonra olduğu anlamına gelir //, en yakın zamanda derlenmiş normal ifade için bir eşleşme için kontrol - match- ve eğer bu değil matchbu olduğu printed.

Bu, satırın yalnızca yazmaması ve önceki satırın yazmaması durumunda yazdırılacağı anlamına gelir . Aynı zamanda es dizileri için gereksiz takaslardan da vazgeçmektedir .match matchmatch

İsteğe bağlı rasgele sayıda satır düşebilecek bir sürüm matchistiyorsanız, biraz daha fazla çalışmaya ihtiyaç duyacak:

printf %s\\n    1 2 3 4 match  \
                match match 8  \
                9 10 11 12 13  \
                14 match match \
                17 18 19 20 21 |
sed -net -e'/match/{h;n;//h;//!H;G;s/\n/&/5;D;}' -ep

... 5'i, kaldırmak istediğiniz satır sayısıyla (eşleşen satır dahil) değiştirin ...


1
2
3
4
12
13
14
21
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.