Bir kalıp eşleşmesinden önceki / sonraki toplam satır sayısını sayma


9

Ben sırayla olmayan IP adresleri, uzun bir liste yaşıyorum. Belirli bir IP adresinden önce / sonra kaç tane IP adresi olduğunu bulmam gerekiyor. Bunu nasıl başarabilirim?


Yinelenen IP'niz var mı?
cuonglm

Hayır. Tüm IP adresleri benzersizdir.
Mandar Shinde

IP adresi için önce / sonra ne anlama geliyor? Özellikle, hem IPv4 hem de IPv6 adresleriniz var mı? Nasıl karşılaştırırlar?
vinc17

Sıralanmış dosyaya mı ihtiyacınız var?
cuonglm

2
@ vinc17 - Dosya yalnızca IP adresleri (IPv4) içeriyor, başka veri yok. Toplamda 1000 IP adresi varsa ve maç 300. konumda bulunursa, maçtan önce 299 satır ve maçtan sonra 700 satır olduğu anlamına gelir.
Mandar Shinde

Yanıtlar:


8

Maç da dahil olmak üzere maçtan önceki ve sonraki satırların sayısı (yani, maçı hariç tutmak istiyorsanız, sonucu 1'den çıkarmanız gerekir):

sed -n '0,/pattern/p' file | wc -l
sed -n '/pattern/,$p' file | wc -l

Ancak bunun özellikle IP adresleri ile ilgisi yoktur.


4

Belki de en kolayı,

sed -n '/pattern/{=; q;}' file

Hatayı gösterdiğin için teşekkürler @JoshepR


Bu sadece desenin oluştuğu satır numarasını yazdırır.
Joseph R.

@JosephR. - hayır, her eşleşmenin gerçekleştiği her satır numarasını yazdırır .
mikeserv

@mikeserv Biliyorum ama OP IP adreslerinin benzersiz olduğunu belirtti . OP aynı zamanda maçların gerçekleştiği satır numarasını da istemez; istedikleri satır sayısını deseni oluşmadan önce ve ondan sonra satır sayısını.
Joseph R.

@JosephR - bu sayılara ulaşmanın en hızlı yolu satır numaralarını hesaplamaktır - bunu doğrudan dckendime, muhtemelen kendime bağlarım .
mikeserv

@mikeserv Bu cevaptaki bilgilerin yararlı olmadığını savunmuyorum, sadece bu kodun kendi başına OP'nin istediklerini yapmadığını söylüyorum.
Joseph R.

3

Bunu en çok sevdiğimi düşünmeme rağmen bunu iki şekilde yaptım

: $(( afterl=( lastl=$(wc -l <~/file) ) - 2 -
  $(( beforel=( matchl=$(sed -n "/$IP/{=;q;}" <~/file) ) - 1
)) ))
for n in last match afters befores
do  printf '%s line%s :\t%d\n' \
        "${n%s}" "${n##*[!s]}" $((${n%s}l))
done

Bu, tüm bunları geçerli kabuk değişkenleri olarak kaydeder ve bunları çıkış için for döngüsünde değerlendirir. Dosyadaki toplam satırları sayar ve wcilk eşleşen satır numarasını alır sed.

Çıkışı:

last line :     1000
match line :    200
after lines :   799
before lines :  199

Ben de yaptım:

sed -n "/$IP/=;\$=" ~/file |  
tr \\n \  | { 
IFS=' ' read ml ll 
printf '%s line%s:\t%d\n' \
    last '' $((ll=${ll##* }))
    match '' $ml \
    after s "$((al=ll-ml-1)) \ 
    before s $((bl=ml-1))
}

sedyalnızca eşleşen ve son satır numaralarını yazdırır, ardından traraya giren \newline'larıVe readilk okur sedbireyin içine sonuçları $mlve içine tüm diğerleri $ll. Olası çoklu eşleşme vakaları, $lldaha sonra tekrar ayarlandığında, genişlemenin son sonucu dışındaki tüm sonuçların çıkarılmasıyla ele alınır .

Çıkışı:

last line :     1000
match line :    200
after lines :   799
before lines :  199

Her iki yöntem de oluşturulan dosyada şu şekilde test edildi:

IP='some string for which I seek' 
for count in 1 2 3 4 5 
do  printf '%.199d%s\n' 0 "$IP" 
done | tr 0 \\n >~/file 

Satır numarasına göre yapar:

  1. arama dizesini ayarlar
  2. Birden fazla eşleşme olmasını sağlamak için beş kez döngüler
  3. 199 sıfır "$IP"sonra bir \newline yazdırır
  4. borular çıktısı tr- sıfırları \newlines'a çevirir~/file

2

İşte bunu yapan biraz Perl kodu:

perl -ne '
     if(1 .. /192\.168\.1\.1/) { $before++ }
     else                      { $after++  }
     $before--; # The matching line was counted
     END{print "Before: $before, After: $after\n"}' your_file

Bu, IP'yi içeren satırdan önceki ve sonraki toplam satır sayısını sayar 192.168.1.1. İstediğiniz IP ile değiştirin.

Bash dışında hiçbir şey kullanmamak:

before=0
match=0
after=0
while read line;do
    if [ "$line" = 192.168.1.1 ];then
        match=1
    elif [ $match -eq 0 ];then
        before=$(($before+1))
    else
        after=$(($after + 1))
    fi
done < your_file
printf "Before: %d, After: %d\n" "$before" "$after"

BASH tercih edilir.
Mandar Shinde

2
@Joseph R .: Neden $.sayaç yerine kullanmıyorsunuz ?
cuonglm

@Gnouc Elbette yapabilirim. Bunu belirlemekten daha okunabilir olduğunu düşünüyorum sadece $afterkadar $. - $before.
Joseph R.

Hayır, yani: çıktısını uyum olursa $. - 1kaydetme, $.için $tmp. Yazdırmayı bitirin $. - $tmp. Yani hem öncesi hem de sonrası için sayaca ihtiyacımız yok. Elbette sizinkinden daha az okunabilir.
cuonglm

@MandarShinde Lütfen düzenlemeye bakın. Saf bir Bash yanıtı ekledim.
Joseph R.

2

Biraz karmaşık olan ancak doğru sonuçlar verecek aşağıdaki komutları deniyordum:

Sonra:

a=$(cat file | wc -l) && b=$(cat -n file | grep <Pattern> | awk '{print $1}') && echo "$a - $b" | bc -l

Önce:

echo "`cat -n file | grep <Pattern> | awk '{print $1}'`-1" | bc -l

2

awkSon maçtan önceki ve sonraki satır sayısını bildiren bir çözüm

awk '/192\.168\.1\.1/{x=NR};{y=NR} END{printf "before-%d, after-%d\n" , x-1, y-x}'  file

1

Grepbelirli bir desenin kaç kez bulunduğunu sayabilen bir özelliğe sahiptir. Bunu -cyapacak komutu kullanırsanız . İle -cve -vkomuta, bu belli bir kalıba uymayan kaç kez sayacaktır

Misal:

grep -c -v <pattern> file

Yani şöyle bir şey denerseniz:

grep -c -v 192.168.x.x file.log bu işe yarayacak.


Bu, hedef IP'nin gerçekleşme sayısını sayar. OP'nin istediği bu değil.
Joseph R.

Sadece düzenledim, eğer belirli bir IP'den önce ve sonra diğer tüm IP'leri saymayı istiyorsa, düzenleme onun için çalışmalıdır.
ryekayo
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.