Bash Script: นับบรรทัดที่ไม่ซ้ำกันในไฟล์


129

สถานการณ์:

ฉันมีไฟล์ขนาดใหญ่ (หลายล้านบรรทัด) ที่มีที่อยู่ IP และพอร์ตจากการดักจับเครือข่ายหลายชั่วโมงหนึ่งพอร์ต / พอร์ตต่อบรรทัด เส้นเป็นรูปแบบนี้:

ip.ad.dre.ss[:port]

ผลลัพธ์ที่ต้องการ:

มีรายการสำหรับแต่ละแพ็กเก็ตที่ฉันได้รับขณะบันทึกดังนั้นจึงมีที่อยู่ที่ซ้ำกันจำนวนมาก ฉันต้องการเรียกใช้สิ่งนี้ผ่านเชลล์สคริปต์บางประเภทซึ่งจะสามารถลดเป็นบรรทัดของรูปแบบได้

ip.ad.dre.ss[:port] count

ซึ่งcountคือจำนวนของการเกิดขึ้นของที่อยู่เฉพาะที่ (และพอร์ต) ไม่ต้องทำงานพิเศษให้ถือว่าพอร์ตต่าง ๆ เป็นที่อยู่ที่แตกต่างกัน

จนถึงตอนนี้ฉันใช้คำสั่งนี้เพื่อขูดที่อยู่ IP ทั้งหมดจากไฟล์บันทึก:

grep -o -E [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(:[0-9]+)? ip_traffic-1.log > ips.txt

จากนั้นฉันสามารถใช้ regex ที่ค่อนข้างง่ายเพื่อขูดที่อยู่ IP ทั้งหมดที่ส่งมาจากที่อยู่ของฉัน (ซึ่งฉันไม่สนใจ)

จากนั้นฉันสามารถใช้สิ่งต่อไปนี้เพื่อแยกรายการที่ไม่ซ้ำกัน:

sort -u ips.txt > intermediate.txt

ฉันไม่รู้ว่าฉันจะรวมการนับบรรทัดด้วยการเรียงลำดับอย่างไร

คำตอบ:


303

คุณสามารถใช้uniqคำสั่งเพื่อรับจำนวนบรรทัดซ้ำที่เรียงลำดับ:

sort ips.txt | uniq -c

เพื่อให้ได้ผลลัพธ์บ่อยที่สุดที่ด้านบน (ขอบคุณ Peter Jaric):

sort ips.txt | uniq -c | sort -bgr

10
ฉันชอบความ-bgrบังเอิญที่ดูเหมือนเป็นเครื่องมือช่วยจำbiggerซึ่งเป็นสิ่งที่เราต้องการในอันดับต้น ๆ
dwanderson

1
เป็นฟังก์ชันขนาดเล็กสำหรับไฟล์.bashrcหรือ.bash_aliasesไฟล์ของคุณ: function countuniquelines () { sort "$1" | uniq -c | sort -bgr; }. โทรตามcountuniquelines myfile.txt.
โยฮัน

sort -nrไม่แน่ใจว่าทำไมไม่ได้
Nakilon

5

ในการนับจำนวนบรรทัดที่ไม่ซ้ำกันทั้งหมด (เช่นไม่พิจารณาบรรทัดที่ซ้ำกัน) เราสามารถใช้uniqหรือ Awk กับwc:

sort ips.txt | uniq | wc -l
awk '!seen[$0]++' ips.txt | wc -l

อาร์เรย์ของ Awk เชื่อมโยงกันดังนั้นจึงอาจทำงานได้เร็วกว่าการเรียงลำดับเล็กน้อย

การสร้างไฟล์ข้อความ:

$  for i in {1..100000}; do echo $RANDOM; done > random.txt
$ time sort random.txt | uniq | wc -l
31175

real    0m1.193s
user    0m0.701s
sys     0m0.388s

$ time awk '!seen[$0]++' random.txt | wc -l
31175

real    0m0.675s
user    0m0.108s
sys     0m0.171s

น่าสนใจ อาจสร้างความแตกต่างอย่างเห็นได้ชัดสำหรับชุดข้อมูลขนาดใหญ่
Wug

1

นี่เป็นวิธีที่เร็วที่สุดในการนับจำนวนบรรทัดที่ซ้ำกันและให้พิมพ์ออกมาอย่างดีโดยเรียงลำดับโดยใช้ความถี่น้อยที่สุดถึงบ่อยที่สุด:

awk '{!seen[$0]++}END{for (i in seen) print seen[i], i}' ips.txt | sort -n

หากคุณไม่สนใจประสิทธิภาพและต้องการสิ่งที่จำง่ายขึ้นให้เรียกใช้:

sort ips.txt | uniq -c | sort -n

PS:

sort -nแยกวิเคราะห์เขตข้อมูลเป็นตัวเลขซึ่งถูกต้องเนื่องจากเรากำลังเรียงลำดับโดยใช้การนับ


!ใน{!seen[$0]++}ซ้ำซ้อนที่นี่ในขณะที่เราเพียง ENDแต่ทำพิมพ์ที่ที่
Amir
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.