นับจำนวนบรรทัดทั้งหมดก่อน / หลังการจับคู่รูปแบบ


9

ฉันมีรายการที่อยู่ IP จำนวนมากซึ่งไม่ได้เรียงตามลำดับ ฉันต้องการค้นหาจำนวนที่อยู่ IP ที่มีอยู่ก่อน / หลังที่อยู่ IP ที่เฉพาะเจาะจง ฉันจะบรรลุสิ่งนี้ได้อย่างไร


คุณมี IP ซ้ำหรือไม่
cuonglm

ไม่ที่อยู่ IP ทั้งหมดนั้นไม่ซ้ำกัน
Mandar Shinde

ก่อน / หลังมีความหมายอย่างไรกับที่อยู่ IP คุณมีทั้งที่อยู่ IPv4 และ IPv6 หรือไม่ พวกเขาเปรียบเทียบอย่างไร
vinc17

คุณต้องการเรียงไฟล์หรือไม่?
cuonglm

2
@ vinc17 - ไฟล์มีเฉพาะที่อยู่ IP (IPv4) เท่านั้นไม่มีข้อมูลอื่นรวมอยู่ด้วย หากมี 1,000 ที่อยู่ IP ทั้งหมดและพบการจับคู่ที่ตำแหน่งที่ 300 หมายความว่ามี 299 บรรทัดก่อนการแข่งขันและ 700 บรรทัดหลังการแข่งขัน
Mandar Shinde

คำตอบ:


8

จำนวนบรรทัดก่อนและหลังการแข่งขันรวมถึงการจับคู่ (เช่นคุณต้องลบ 1 จากผลลัพธ์หากคุณต้องการยกเว้นการแข่งขัน):

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

แต่สิ่งนี้ไม่เกี่ยวข้องกับที่อยู่ IP โดยเฉพาะ


4

บางทีสิ่งที่ง่ายที่สุดคือ

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

ขอบคุณ @JoshepR สำหรับการชี้ข้อผิดพลาด


นี่แค่พิมพ์หมายเลขบรรทัดที่รูปแบบเกิดขึ้น
โจเซฟอาร์

@JosephR - ไม่มันพิมพ์ทุกหมายเลขบรรทัดที่ทุกการแข่งขันเกิดขึ้น
mikeserv

@mikeserv ฉันรู้ แต่ OP ระบุว่าที่อยู่ IP ไม่ซ้ำกัน OP ยังไม่ต้องการหมายเลขบรรทัดที่เกิดการแข่งขัน พวกเขาต้องการจำนวนบรรทัดก่อนรูปแบบที่เกิดขึ้นและจำนวนบรรทัดหลังจากนั้น
โจเซฟอาร์

@JosephR - วิธีที่เร็วที่สุดที่จะไปถึงจำนวนเหล่านั้นคือการนับหมายเลขบรรทัด - ฉันจะทำสิ่งนี้กับdcตัวเองโดยตรงอาจเป็นไปได้
mikeserv

@mikeserv ฉันไม่ได้โต้เถียงว่าข้อมูลจากคำตอบนี้ไม่มีประโยชน์ฉันแค่บอกว่ารหัสนี้ด้วยตัวของมันเองไม่ได้ทำในสิ่งที่ OP ต้องการ
โจเซฟอาร์

3

ฉันทำสองวิธีนี้ แต่ฉันคิดว่าฉันชอบสิ่งนี้ที่สุด:

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

นั่นจะบันทึกสิ่งเหล่านั้นทั้งหมดเป็นตัวแปรเชลล์ปัจจุบัน - และประเมินพวกมันใน for for loop หลังจากนั้นสำหรับ output มันนับเส้นรวมในไฟล์ที่มีและได้รับหมายเลขบรรทัดแรกที่จับคู่กับwcsed

เอาท์พุท:

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

ฉันก็ทำเช่นนั้น:

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

sedพิมพ์หมายเลขที่ตรงกันและบรรทัดสุดท้ายเท่านั้นจากนั้นtrแปล\newlines ที่แทรกเข้าไปและreadอ่านครั้งแรกของsedผลการค้นหา 's เข้า$mlและอื่น ๆ $llทั้งหมดลง การจับคู่แบบหลายกรณีที่เป็นไปได้จะถูกจัดการโดยการดึงทั้งหมด แต่ผลลัพธ์สุดท้ายจากการ$llขยายเมื่อตั้งค่าอีกครั้งในภายหลัง

เอาท์พุท:

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

ทั้งสองวิธีถูกทดสอบบนไฟล์ที่สร้างด้วยวิธีต่อไปนี้:

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 

มันทำโดยหมายเลขบรรทัด:

  1. ตั้งค่าสตริงการค้นหา
  2. วนซ้ำห้าครั้งเพื่อให้แน่ใจว่าจะมีการแข่งขันหลายครั้ง
  3. พิมพ์ 199 ศูนย์จาก"$IP"นั้น\newline
  4. ท่อส่งออกไปtr- ซึ่งแปลเป็นศูนย์\newlines แล้วเป็น~/file

2

นี่คือโค้ด Perl เล็กน้อยที่ทำ:

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

192.168.1.1นี้นับจำนวนของเส้นก่อนและหลังบรรทัดที่มีทรัพย์สินทางปัญญา แทนที่ด้วย IP ที่คุณต้องการ

ไม่ใช้อะไรนอกจาก 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
Mandar Shinde

2
@Joseph R .: ทำไมคุณไม่ใช้$.แทนตัวนับ
cuonglm

@Gnouc แน่นอนฉันสามารถ ผมแค่คิดว่านี่คือการอ่านมากขึ้นกว่าการตั้งค่าไป$after $. - $before
โจเซฟอาร์

ไม่ฉันหมายถึง: ถ้าจับคู่พิมพ์$. - 1บันทึกไป$. พิมพ์$tmp End $. - $tmpดังนั้นเราไม่ต้องการตัวนับทั้งก่อนและหลัง แน่นอนว่ามันอ่านได้น้อยกว่าของคุณ
cuonglm

@MandarShinde โปรดดูการแก้ไข ฉันเพิ่มคำตอบ Bash บริสุทธิ์
โจเซฟอาร์

2

ฉันลองคำสั่งต่อไปนี้ซึ่งค่อนข้างซับซ้อน แต่จะให้ผลลัพธ์ที่แม่นยำ:

หลังจาก:

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

ก่อน:

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

2

awkวิธีการแก้ปัญหาการรายงานจำนวนเส้นก่อนและหลังการแข่งขันที่ผ่านมา

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

1

Grepมีคุณสมบัติที่สามารถนับจำนวนครั้งที่พบรูปแบบเฉพาะ หากคุณใช้-cคำสั่งที่จะทำเช่นนั้น ด้วยการ-cและ-vคำสั่งนี้จะนับจำนวนครั้งนี้ไม่ตรงกับรูปแบบเฉพาะ

ตัวอย่าง:

grep -c -v <pattern> file

ดังนั้นหากคุณลองทำสิ่งที่ชอบ:

grep -c -v 192.168.x.x file.log ที่ควรได้ผล


สิ่งนี้จะนับจำนวนการเกิดของ IP เป้าหมาย นี่ไม่ใช่สิ่งที่ OP ร้องขอ
โจเซฟอาร์

ฉันเพิ่งแก้ไขถ้าเขาขอให้นับ IP อื่น ๆ ทั้งหมดก่อนและหลัง IP เฉพาะการแก้ไขควรทำงานให้เขา
ryekayo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.