Hitung jumlah total garis sebelum / setelah kecocokan pola

9

Saya memiliki daftar panjang alamat IP, yang tidak berurutan. Saya perlu menemukan berapa banyak alamat IP yang ada sebelum / sesudah alamat IP tertentu. Bagaimana saya bisa mencapai ini?

Mandar Shinde
sumber
Apakah Anda memiliki duplikat IP?
cuonglm
Tidak. Semua alamat IP unik.
Mandar Shinde
Apa arti sebelum / sesudah untuk alamat IP? Secara khusus, apakah Anda memiliki alamat IPv4 dan IPv6? Bagaimana mereka membandingkan?
vinc17
Apakah Anda perlu file diurutkan?
cuonglm
2
@ vinc17 - File hanya berisi alamat IP (IPv4), tidak ada data lain yang disertakan. Jika ada 1000 alamat IP secara total, dan kecocokan ditemukan di lokasi ke-300, berarti ada 299 baris sebelum pertandingan dan 700 baris setelah pertandingan.
Mandar Shinde

Jawaban:

8

Jumlah baris sebelum dan sesudah pertandingan, termasuk pertandingan (yaitu Anda harus mengurangi 1 dari hasil jika Anda ingin mengecualikan pertandingan):

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

Tetapi ini tidak ada hubungannya dengan alamat IP pada khususnya.

vinc17
sumber
4

Mungkin yang paling mudah adalah,

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

Terima kasih @ JoshepR untuk menunjukkan kesalahan

jpmuc
sumber
Ini hanya mencetak nomor baris di mana pola terjadi.
Joseph R.
@ JosephRR. - tidak, itu mencetak setiap nomor baris di mana setiap pertandingan terjadi.
mikeserv
@ mikeserv Saya tahu tetapi OP menetapkan bahwa alamat IP unik. OP juga tidak ingin nomor baris tempat pertandingan terjadi; mereka menginginkan jumlah garis sebelum pola terjadi dan jumlah garis setelahnya.
Joseph R.
@ JosephephR - cara tercepat untuk sampai pada penghitungan itu adalah dengan menghitung angka-angka garis - Saya hanya akan menyalurkan ini langsung ke dc, saya sendiri, mungkin.
mikeserv
@ mikeserv Saya tidak berpendapat bahwa informasi dari jawaban ini tidak berguna, saya hanya mengatakan bahwa kode ini sendiri tidak melakukan apa yang diinginkan OP.
Joseph R.
3

Saya melakukan dua cara ini, meskipun saya pikir saya paling suka ini:

: $(( 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

Itu menyimpan semua itu sebagai variabel shell saat ini - dan mengevaluasi mereka dalam for for loop kemudian untuk output. Itu menghitung total baris dalam file dengan wcdan mendapat nomor baris pertama yang cocok dengannya sed.

Keluarannya:

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

Saya juga melakukan:

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))
}

sedhanya mencetak nomor baris yang cocok dan terakhir, kemudian trmenerjemahkan \newlines yang akan diintervensi, dan readmembaca hasil pertama sedke dalam $mldan semua yang lain ke dalam $ll. Beberapa kasus pencocokan mungkin ditangani dengan melepaskan semua kecuali hasil terakhir dari $llekspansi saat mengaturnya kembali nanti.

Keluarannya:

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

Kedua metode diuji pada file yang dihasilkan dengan cara berikut:

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 

Ya, dengan nomor baris:

  1. mengatur string pencarian
  2. loop lima kali untuk memastikan akan ada beberapa pertandingan
  3. mencetak 199 angka nol maka "$IP"kemudian \newline
  4. output pipa ke tr- yang menerjemahkan nol ke \newlines lalu ke~/file
mikeserv
sumber
2

Berikut sedikit kode Perl yang melakukannya:

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

Ini menghitung jumlah total baris sebelum dan sesudah baris yang berisi IP 192.168.1.1. Ganti dengan IP yang Anda inginkan.

Hanya menggunakan Bash:

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"
Joseph R.
sumber
BASH lebih disukai.
Mandar Shinde
2
@ Joseph R .: Mengapa Anda tidak menggunakan $.konter?
cuonglm
@ Gnouc tentu saja saya bisa. Saya hanya berpikir ini lebih mudah dibaca daripada pengaturan $afteruntuk $. - $before.
Joseph R.
Tidak, maksud saya: jika cocok, cetak $. - 1, simpan $.ke $tmp. Cetak akhir $. - $tmp. Jadi kita tidak perlu kontra untuk sebelum dan sesudah. Tentu saja itu kurang mudah dibaca daripada milik Anda.
cuonglm
@MandarShinde Silakan lihat hasil edit. Saya menambahkan jawaban Bash murni.
Joseph R.
2

Saya mencoba perintah berikut, yang sedikit rumit, tetapi akan memberikan hasil yang akurat:

Setelah:

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

Sebelum:

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

Sebuah awksolusi melaporkan jumlah baris sebelum dan setelah pertandingan terakhir

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

Grepmemiliki fitur yang dapat menghitung berapa kali pola tertentu ditemukan. Jika Anda menggunakan -cperintah yang akan melakukannya. Dengan -cdan -vperintah, ini akan menghitung berapa kali ini tidak cocok dengan pola tertentu

Contoh:

grep -c -v <pattern> file

Jadi, jika Anda mencoba sesuatu seperti:

grep -c -v 192.168.x.x file.log itu seharusnya bekerja.

ryekayo
sumber
Ini menghitung jumlah kemunculan IP target. Ini bukan yang diminta OP.
Joseph R.
Saya baru saja mengeditnya, jika dia meminta untuk menghitung semua IP lain sebelum dan setelah IP tertentu, hasil edit harus bekerja untuknya.
ryekayo