Đếm tổng số dòng trước / sau khi khớp mẫu


9

Tôi đang có một danh sách dài các địa chỉ IP không theo thứ tự. Tôi cần tìm xem có bao nhiêu địa chỉ IP trước / sau một địa chỉ IP cụ thể. Làm thế nào tôi có thể đạt được điều này?


Bạn có IP trùng lặp?
cuonglm

Không. Tất cả các địa chỉ IP là duy nhất.
Mandar Shinde

Trước / sau có nghĩa là gì đối với một địa chỉ IP? Cụ thể, bạn có cả địa chỉ IPv4 và IPv6 không? Làm thế nào để họ so sánh?
vinc17

Bạn có cần các tập tin sắp xếp?
cuonglm

2
@ vinc17 - Tệp chỉ chứa địa chỉ IP (IPv4), không có dữ liệu nào khác được đưa vào. Nếu có tổng cộng 1000 địa chỉ IP và tìm thấy kết quả trùng khớp ở vị trí thứ 300, có nghĩa là có 299 dòng trước trận đấu và 700 dòng sau trận đấu.
Mandar Shinde

Câu trả lời:


8

Số dòng trước và sau trận đấu, bao gồm cả trận đấu (tức là bạn cần trừ 1 khỏi kết quả nếu bạn muốn loại trừ trận đấu):

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

Nhưng điều này không liên quan gì đến địa chỉ IP nói riêng.


4

Có lẽ dễ nhất là

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

Cảm ơn @JoshepR đã chỉ ra lỗi


Điều này chỉ in số dòng mà mô hình xảy ra.
Joseph R.

@JosephR. - không, nó in mọi số dòng trên đó mọi trận đấu xảy ra.
mikeerv

@mikeerv Tôi biết nhưng OP chỉ định rằng địa chỉ IP là duy nhất. OP cũng không muốn số dòng nơi xảy ra (các) trận đấu; họ muốn số lượng dòng trước khi mẫu xuất hiện số dòng sau nó.
Joseph R.

@JosephR - cách nhanh nhất để đạt được số lượng đó là kiểm đếm số dòng - tôi có thể chỉ cần đưa trực tiếp điều này đến dc, bản thân tôi, có lẽ.
mikeerv

@mikeerv Tôi không cho rằng thông tin từ câu trả lời này không hữu ích, tôi chỉ nói rằng mã này tự nó không làm những gì OP muốn.
Joseph R.

3

Tôi đã làm điều này theo hai cách, mặc dù tôi nghĩ rằng tôi thích điều này nhất:

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

Điều đó lưu tất cả những cái đó như các biến shell hiện tại - và đánh giá chúng trong vòng lặp for sau đó cho đầu ra. Nó đếm tổng số dòng trong tệp wcvà nhận được số dòng phù hợp đầu tiên với sed.

Đầu ra của nó:

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

Tôi cũng đã là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))
}

sedchỉ in các số dòng phù hợp và cuối cùng, sau đó trdịch các \newlines can thiệp sangreadđọc sedkết quả đầu tiên vào $mlvà tất cả những kết quả khác $ll. Nhiều trường hợp khớp có thể được xử lý bằng cách tước tất cả trừ kết quả cuối cùng ra khỏi bản $llmở rộng khi thiết lập lại sau.

Đầu ra của nó:

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

Cả hai phương pháp đều được kiểm tra trên tệp được tạo theo cách sau:

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 

Nó không, theo số dòng:

  1. đặt chuỗi tìm kiếm
  2. vòng lặp năm lần để đảm bảo sẽ có nhiều trận đấu
  3. in 199 số 0 rồi "$IP"đến \newline
  4. ống dẫn ra tr- dịch các số 0 thành \newlines sau đó vào~/file

2

Đây là một ít mã Perl thực hiện điều đó:

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

Điều này đếm tổng số dòng trước và sau dòng chứa IP 192.168.1.1. Thay thế bằng IP mong muốn của bạn.

Không dùng gì ngoài 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"

BASH được ưa thích.
Mandar Shinde

2
@Joseph R.: Tại sao bạn không sử dụng $.thay vì quầy?
cuonglm

@ Tất nhiên tôi có thể. Tôi chỉ nghĩ rằng đây là dễ đọc hơn so thiết $afterđể $. - $before.
Joseph R.

Không, ý tôi là: nếu khớp, in $. - 1, lưu $.vào $tmp. Kết thúc in $. - $tmp. Vì vậy, chúng tôi không cần truy cập cho cả trước và sau. Tất nhiên nó ít đọc hơn của bạn.
cuonglm

@MandarShinde Vui lòng xem chỉnh sửa. Tôi đã thêm một câu trả lời Bash thuần túy.
Joseph R.

2

Tôi đã thử các lệnh sau, hơi phức tạp, nhưng sẽ cho kết quả chính xác:

Sau:

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

Trước:

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

2

Một awkgiải pháp báo cáo số lượng dòng trước và sau trận đấu cuối cùng

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

1

Grepcó một tính năng có thể đếm số lần một mẫu cụ thể được tìm thấy. Nếu bạn sử dụng -clệnh sẽ làm như vậy. Với lệnh -cand -v, điều này sẽ tính số lần không khớp với một mẫu cụ thể

Thí dụ:

grep -c -v <pattern> file

Vì vậy, nếu bạn thử một cái gì đó như:

grep -c -v 192.168.x.x file.log Cần làm việc.


Điều này đếm số lần xuất hiện của IP mục tiêu. Đây không phải là những gì OP yêu cầu.
Joseph R.

Tôi chỉ chỉnh sửa nó, nếu anh ta yêu cầu đếm tất cả các IP khác trước và sau một IP cụ thể, việc chỉnh sửa sẽ hoạt động với anh ta.
ryekayo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.