Sed ile bir dosyadaki tüm olayları bul


15

OPEN STEP 4.2 OS Kullanılıyor ... Şu anda aşağıdaki sedKomutu kullanıyorum :

sed -n '1,/141.299.99.1/p' TESTFILE | tail -3

Bu komut, 141.299.99.1 ipli bir dosyada bir örnek bulur ve ayrıca IP'nin tüm örneklerini ve ondan önceki 3 satırı da bulmak istediğim hariç, hepsi iyi olan 3 satır içerir. ve sadece ilki değil.


1
Lütfen daima işletim sisteminizi ekleyin. Çözümler sıklıkla kullanılan İşletim Sistemine bağlıdır. Unix, Linux, BSD, OSX, başka bir şey kullanıyor musunuz? Hangi versiyon?
terdon

BÜYÜK NOKTA! Açık Adım 4.2'yi kullanmak oldukça eskidir ve dahil edilen kabuklar aşağıdaki cevaplarda belirtilen özelliklerin çoğunu içermez.
Dale

Meraktan - OPEN STEP 4.2 sistemi nedir ve bugün için ne kullanılır?
Thorbjørn Ravn Andersen

(ve Perl mevcutsa, bununla gerçekten çok güzel şeyler yapabilirsiniz)
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen Belki de budur: en.wikipedia.org/wiki/OpenStep
Barmar

Yanıtlar:


4

İşte bu GNU sed örneğinegrep -B3 dayanan (ancak umarım POSIX uyumlu - @ StéphaneChazelas'a teşekkür ederek) sed hareketli bir pencere kullanarak taklit etme girişimi :

sed -e '1h;2,4{;H;g;}' -e '1,3d' -e '/141\.299\.99\.1/P' -e '$!N;D' file

İlk iki ifade, çok satırlı bir desen arabelleği doldurur ve ilk eşlemeden önce 3'ten daha az önceki bağlamın bulunduğu kenar durumunu işlemesine izin verir. Orta (normal ifade eşleşmesi) ifadesi, istenen eşleşme metni desen arabelleğinden yukarı çıkıncaya kadar pencerenin üstünden bir satır yazdırır. Son $!N;Dpencere, girişin sonuna ulaşması dışında pencereyi bir satır kaydırır.


-eGNU'ya özgü değildir. POSIX / taşınabilir olmak için, ihtiyacınız olan hiçbir şey olamayacağı için }(ve ;ondan önce bir ihtiyacınız var) buna ihtiyacınız var .
Stéphane Chazelas

Teşekkürler @ StéphaneChazelas - Yani POSIX / taşınabilir olmak için, ilk grubun bölünmesi / değiştirilmesi gerektiği -e '1h;2,4{H;g;}' -e '1,3d'mi söylüyorsunuz ? Test etmek için GNU olmayan bir sistemim yok (ve GNU sed --posixanahtarı umursamıyor gibi görünüyor).
steeldriver

1
Evet, Linux'ta, sedgeleneksel Unix sed'in soyundan olan yadigarı araç testinden farklı bir uygulamayı test edebilirsiniz . İçin POSIX / Unix Spec sedolan pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html
Stéphane Chazelas

Bu iki olayda bulunamadı olay alıyorum: N; D ': Olay bulunamadı. Bir yerde sözdizimi eksik mi? Teşekkürler!!
Dale

Maalesef, en son düzenlememin ilk -e ifadesinden sonra kapanış tekli bir teklifi atladığını fark ettim. Şimdi düzelttim - yukarıdaki ifadeyle tekrar deneyebilir misiniz lütfen?
steeldriver

10

grep bundan daha iyi bir iş çıkarır:

grep -B 3 141.299.99.1 TESTFILE

-B 3Aracı her maç öncesi üç çizgi yazdırmak için. Bu, --her satır grubu arasında yazdırılacaktır . Bunu devre dışı bırakmak için de kullanın --no-group-separator.

Bu -Bseçenek GNUgrep ve çoğu BSD sürümü tarafından da desteklenmektedir ( OSX , FreeBSD , OpenBSD , NetBSD ), ancak teknik olarak standart bir seçenek değildir.


1
Michael Homer - Teşekkürler. - B seçeneğim yok. Başka fikir var mı?
Dale

@Dale GNU grep'i kurabilir misiniz? Bu size seçenek sunacaktır.
Barmar

9

İle sedbir sürgülü pencere yapabilirsiniz.

sed '1N;$!N;/141.299.99.1/P;D'

Bunu yapar. Ama dikkat - alıntı bilebash genişleyen deli davranış ! ! komut geçmişinizden komut dizesine girmeniz biraz delirebilir. Durumun bu set +H;olduğunu tespit ederseniz , komutun önüne önek koyun . Daha sonra yeniden etkinleştirmek için (ancak neden ???) daha set -Hsonra yapın.

Eğer Yani, eğer tabii ki, sadece geçerli olacak edildi kullanarak bash- Senden inanmıyorum gerçi. Ben oldukça belli çalışmakta olduğunuz csh- (kimin deli davranış kabuk olur ki bashc kabuk aldı aşırı geçmişi genişleme öykünür, ama belki değil) . Yani muhtemelen bir \!çalışması gerekir. Umuyorum.

Hepsi taşınabilir kod: POSIX üç operatörünü şöyle anlatıyor : (ancak bu açıklamanın 2001 gibi erken bir zamanda var olduğunu doğruladığımı belirtmek gerekir)

[2addr]NEklenen materyali orijinal materyalden ayırmak için \ngömülü bir \newline kullanarak, sondaki ewline değerini azaltarak bir sonraki girdi satırını desen alanına ekleyin. Geçerli satır numarasının değiştiğini unutmayın.

[2addr]P İlk \newline'a kadar desen boşluğunu standart çıktıya yazın.

[2addr]D İlk \newline boyunca desen alanının başlangıç ​​segmentini silin ve sonraki döngüye başlayın.

İlk satırda desen alanına ekstra bir çizgi eklersiniz, bu yüzden şöyle görünür:

^line 1s contents\nline 2s contents$

Sonra ilk satırda ve sonraki her satırda - sonuncusu hariç - desen alanına başka bir satır eklersiniz . Yani şöyle görünüyor:

^line 1\nline 2\nline 3$

IP adresiniz içinizde bulunursa P, ilk yeni satıra kadar inin, bu yüzden burada sadece 1. satır. Her döngünün sonunda Daynı şeyi seçiyor ve geriye kalanlarla başlıyorsunuz. Bir sonraki döngü şöyle görünür:

^line 2\nline 3\nline 4$

...ve bunun gibi. IP'niz bu üç taneden herhangi birinde bulunursa, en eskisi yazdırılır - her seferinde. Yani her zaman sadece üç satır ilerdesiniz.

İşte kısa bir örnek. Sıfırla biten her sayı için üç satırlı bir tampon yazdırılır:

seq 10 52 | sed '1N;$!N;/0\(\n\|$\)/P;D'

10
18
19
20
28
29
30
38
39
40
48
49
50

Bu sizin durumunuzdan biraz daha karmaşıktır çünkü probleminize daha yakından benzemek için 0\nyeni satırdan veya 0$desen alanının sonundan geçmek zorunda kaldım - ancak bunun bir çapa gerektirdiği için farklıdırlar - bu biraz zor olabilir desen-alanı sürekli değişir.

Çapanın esnek olduğu sürece çıktının da olduğunu göstermek için 10 ve 52'lik garip vakaları kullandım. Tamamen portatif olarak, algoritmaya güvenerek aynı sonuçları elde edebilirim:

seq 10 52 | sed '1N;$!N;/[90]\n/P;D'

Ve penceremi kısıtlarken aramayı genişlet - 0'dan 9'a ve 0'a ve 3 satırdan ikiye.

Herneyse, sen anladın.


Bütün sıkı çalışman için teşekkürler. Maalesef, aramasını istediğim dosya adını nereye koyacağım?
Dale

@Dale - benim hatam. sed '...' $filename. Bu arada - kendi arama dizenizden noktalarda ayrıldım, ancak bunlar aslında bir desende nokta değil - bunlar herhangi bir karakteri temsil ediyor. Muhtemelen oct\.oct\.oct\.octonlardan kaçmalısın, böylece sadece periyotlarla eşleşirler.
mikeserv

Ben onunla kedi ve farklı <> sembolleri denedim ve burada diğer çözümler ile aldığım olay bulunamadı bu yüzden OS benim bu çözümler ile uyumlu değil merak ediyorum.
Dale

şimdi -> N; /141.299.99.1/P; D 'ile sonuçlanıyor: Etkinlik bulunamadı.
Dale

@Dale - lütfen güncellemeye bakın. Size yardımcı olmalı.
mikeserv

4

Yana Sözünü sen olmadığını -Bseçeneği grep, sen Perl kullanabilirsiniz (örneğin) 4 satır kayan bir pencere yapmak:

perl -ne '
    push @window,$_;
    shift @window if @window > 4;
    print @window if /141\.299\.99\.1/
' your_file

Ramesh'in cevabı benzer bir şey yapıyor awk.


Perl sürümümün bunu destekleyip desteklemediğinden emin değilim ama bunu deneyeceğim. Soruma cevap vermek için zaman ayırdığınız için çok teşekkür ederim - çok minnettarım!
Dale

@ Dale Çok hoş geldiniz. Bu kod herhangi bir son teknoloji Perl özelliklerini kullanır şüphe.
Joseph R.

4

Mümkün olduğunda pcregrep kullanabilirsiniz :

pcregrep -M '.*\n.*\n.*\n141.299.99.1' file

PCREGREP olup olmadığımı kontrol etme. Komutun kompaktlığını seviyorum. Zaman ve çabalarınız için çok minnettarım. Teşekkür ederim!!!
Dale

4

Kabuğun kendisindeki diğer grep olmayan cevaplarla aynı temel yaklaşımı uygulayabilirsiniz (bu, destekleyen nispeten yeni bir kabuk olduğunu varsayar =~):

while IFS= read -r line; do 
    [[ $line =~ 141.299.99.1 ]] && printf "%s\n%s\n%s\n%s\n" $a $b $c $line;
    a=$b; b=$c; c=$line; 
done < file 

Alternatif olarak, tüm dosyayı bir diziye karıştırabilirsiniz:

perl -e '@F=<>; 
        for($i=0;$i<=$#F;$i++){
          print $F[$i-3],$F[$i-2],$F[$i-1],$F[$i] if $F[$i]=~/141.299.99.1/
        }' file 

Kabuğum çok eski - Steve Jobs Open Step. Harika bir fikir olsa ve zaman ayırdığınız için teşekkür ederiz !!! Dale
Dale

@ Perl perl yaklaşımı hemen hemen her yerde çalışır. Lütfen bize işletim sisteminizi (sorunuza ekleyin) bu şekilde sizin için işe yarayacak şeyler önerebileceğimizi söyleyin.
terdon

Perl'inizi kopyalayıp NotePad'e koyar ve bir satıra koyarsam çalışır! Soru - istesem maç düzeninden 10 satır önce 3 ila 10'u nerede değiştirebilirim? Teşekkürler!
Dale

Daha fazla $ F [$ iX], ifadeler ekleyerek daha fazla satır ekleyebileceğimi görüyorum. Teşekkürler!
Dale

4

Sisteminiz grepbağlamı desteklemiyorsa , bunun yerine ack-grep'i deneyebilirsiniz :

ack -B 3 141.299.99.1 file

ack programcılar için optimize edilmiş grep gibi bir araçtır.


Komutun kompaktlığını seviyorum, ancak sistemim man sayfalarına bakarken ack'u desteklemiyor. Harika bir fikir ve zaman ayırdığınız için çok teşekkür ederim !!! Dale
Dale

@Dale: Şaşırtıcı! İşletim sisteminiz nedir? Eğer varsa perl, kullanabilirsiniz ack.
cuonglm

2
awk '/141.299.99.1/{for(i=1;i<=x;)print a[i++];print} {for(i=1;i<x;i++)
     a[i]=a[i+1];a[x]=$0;}'  x=3 filename

Bu awkçözümde, geçerli kalıptan önce her zaman 3 satır içerecek bir dizi kullanılır. Dolayısıyla, desen eşleştirildiğinde, dizi içeriği geçerli desenle birlikte yazdırılır.

Test yapmak

-bash-3.2$ cat filename
10.0.0.1
10.0.0.2
10.0.0.3
10.0.0.4
141.299.99.1
10.0.0.5
10.0.0.6
10.0.0.7
10.0.0.8
10.0.0.9
10.0.0.10
141.299.99.1
10.0.0.11
10.0.0.12
10.0.0.13
10.0.0.14
10.0.0.15
10.0.0.16
141.299.99.1
10.0.0.17
10.0.0.18
10.0.0.19

Komutu yürüttükten sonra çıktı,

10.0.0.2
10.0.0.3
10.0.0.4
141.299.99.1
10.0.0.8
10.0.0.9
10.0.0.10
141.299.99.1
10.0.0.14
10.0.0.15
10.0.0.16
141.299.99.1

çok ayrıntılı - çok teşekkür ederim. Bir deneyeceğim. Zaman ayırdığınız için çok minnettarım !! Dale
Dale

Bir test dosyam var ve çözümünüz çalışıyor! Sorun büyük üretim dosyamda çalıştırdığımda, çıkışın komutla çalışamaması için Çok Uzun Kayıt Numarası ile geri geliyor. Bu sayfanın üst kısmındaki orijinal komutum çalışıyor, ancak yalnızca bir örneği buluyor. Yardımın için minnettarım. Birden fazla instatnce bulmasını sağlamak için orijinal komutumla yapabileceğim bir şey var mı?
Dale

1

Bunların çoğunda, /141.299.99.1/aynı zamanda maç olacak (örn) 141a299q99+1veya 141029969951çünkü .normal ifadede herhangi bir karakter temsil edebilir.

Kullanılması /141[.]299[.]99[.]1/daha güvenli olduğunu ve emin uymuyor başında ek bağlam eklemek ve yapmak bütün regexp'nin sona erebilir 3141., .12, .104vb


1
Bu iyi bir nokta - ve ben de düşündüm. Yine de, asker tarafından sağlanan ipi bilinen bir çalışma maçı olarak kullandım ve fırsat verildiğinde ona aynı şeyi bildirdim. Her neyse - bunların hepsi değil - steeldriver'ın cevabı char maçını baştan beri alıntıladı.
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.