นับจำนวนครั้งที่เกิดขึ้นของรูปแบบในไฟล์ (แม้ในบรรทัดเดียวกัน)


94

เมื่อค้นหาจำนวนครั้งของสตริงในไฟล์โดยทั่วไปฉันจะใช้:

grep pattern file | wc -l

อย่างไรก็ตามสิ่งนี้พบเพียงหนึ่งครั้งต่อบรรทัดเนื่องจากวิธีการทำงานของ grep ฉันจะค้นหาจำนวนครั้งที่สตริงปรากฏในไฟล์ได้อย่างไรไม่ว่าสตริงจะอยู่ในบรรทัดเดียวกันหรือต่างกัน

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

คำตอบ:


158

-oการนับเหตุการณ์ทั้งหมดใช้ ลองสิ่งนี้:

echo afoobarfoobar | grep -o foo | wc -l

และman grepแน่นอน (:

อัปเดต

บางคนแนะนำให้ใช้เพียงแทนgrep -co foogrep -o foo | wc -l

อย่า.

ทางลัดนี้จะใช้ไม่ได้ในทุกกรณี หน้าคนพูดว่า:

-c print a count of matching lines

ความแตกต่างในแนวทางเหล่านี้แสดงไว้ด้านล่าง:

1.

$ echo afoobarfoobar | grep -oc foo
1

ทันทีที่พบการจับคู่ในบรรทัด ( a{foo}barfoobar) การค้นหาจะหยุดลง 1เพียงหนึ่งบรรทัดถูกตรวจสอบและการจับคู่เพื่อให้ออกเป็น ที่จริง-oจะถูกข้ามไปที่นี่และคุณสามารถใช้grep -cแทนได้

2.

$ echo afoobarfoobar | grep -o foo
foo
foo

$ echo afoobarfoobar | grep -o foo | wc -l
2

พบสองรายการที่ตรงกันในบรรทัด ( a{foo}bar{foo}bar) เนื่องจากเราขอให้ค้นหาทุกเหตุการณ์ที่เกิดขึ้น ( -o) อย่างชัดเจน ทุกครั้งที่เกิดขึ้นจะถูกพิมพ์บนบรรทัดที่แยกจากกันและwc -lนับจำนวนบรรทัดในเอาต์พุตเท่านั้น


1
ว้าว ... มันง่ายขนาดนั้นเลยเหรอ?
jrdioko

1
grep -oc ไม่ทำงานในกรณีนี้ ลอง echo afoobarfoobar | grep -oc foo
Paulus

ไม่มีวิธีดำเนินการนี้สำหรับหลายไฟล์หรือไม่? สมมติว่าฉันต้องการดูจำนวนครั้งที่เกิดขึ้นต่อไฟล์ในชุดไฟล์ ฉันสามารถทำต่อบรรทัดด้วย grep -c * แต่ไม่ใช่ต่ออินสแตนซ์
Keith Tyler

grep -o foo a.txt b.txt | sort | uniq -cใช้งานได้ดี (กับ GNU grep): gist.github.com/hudolejev/81a05791f38cbacfd4de3ee3b44eb4f8
hudolejev

2

ลองสิ่งนี้:

grep "string to search for" FileNameToSearch | cut -d ":" -f 4 | sort -n | uniq -c

ตัวอย่าง:

grep "SMTP connect from unknown" maillog | cut -d ":" -f 4 | sort -n | uniq -c
  6  SMTP connect from unknown [188.190.118.90]
 54  SMTP connect from unknown [62.193.131.114]
  3  SMTP connect from unknown [91.222.51.253]

1

โพสต์ล่าช้า:
ใช้รูปแบบ regex การค้นหาเป็นตัวคั่นระเบียน (RS) ในawk
สิ่งนี้ช่วยให้ regex ของคุณสามารถขยาย\nบรรทัดที่ จำกัด ได้ (หากคุณต้องการ)

printf 'X \n moo X\n XX\n' | 
   awk -vRS='X[^X]*X' 'END{print (NR<2?0:NR-1)}'

0

Ripgrepซึ่งเป็นทางเลือกที่รวดเร็วสำหรับ grep เพิ่งเปิดตัว--count-matchesธงที่อนุญาตให้นับการแข่งขันแต่ละครั้งในเวอร์ชัน 0.9 (ฉันใช้ตัวอย่างข้างต้นเพื่อให้สอดคล้องกัน):

> echo afoobarfoobar | rg --count foo
1
> echo afoobarfoobar | rg --count-matches foo
2

ตามที่ OP ถาม ripgrep อนุญาตให้ใช้รูปแบบ regex ได้เช่นกัน ( --regexp <PATTERN>) นอกจากนี้ยังสามารถพิมพ์การจับคู่ (บรรทัด) แต่ละรายการในบรรทัดแยกกัน

> echo -e "line1foo\nline2afoobarfoobar" | rg foo
line1foo
line2afoobarfoobar

-1

แฮ็กฟังก์ชันสีของ grep และนับจำนวนแท็กสีที่พิมพ์ออกมา:

echo -e "a\nb  b b\nc\ndef\nb e brb\nr" \
| GREP_COLOR="033" grep --color=always  b \
| perl -e 'undef $/; $_=<>; s/\n//g; s/\x1b\x5b\x30\x33\x33/\n/g; print $_' \
| wc -l
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.