Đếm số lần xuất hiện của một mẫu trong tệp (thậm chí trên cùng một dòng)


94

Khi tìm kiếm số lần xuất hiện của một chuỗi trong tệp, tôi thường sử dụng:

grep pattern file | wc -l

Tuy nhiên, điều này chỉ tìm thấy một lần xuất hiện trên mỗi dòng, do cách thức hoạt động của grep. Làm cách nào để tôi có thể tìm kiếm số lần một chuỗi xuất hiện trong một tệp, bất kể chúng nằm trên cùng một dòng hay khác dòng?

Ngoài ra, nếu tôi đang tìm kiếm một mẫu regex, không phải một chuỗi đơn giản thì sao? Làm cách nào tôi có thể đếm chúng, hoặc thậm chí tốt hơn, in từng kết quả trùng khớp trên một dòng mới?

Câu trả lời:


157

Để đếm tất cả các lần xuất hiện, hãy sử dụng -o. Thử cái này:

echo afoobarfoobar | grep -o foo | wc -l

man greptất nhiên (:

Cập nhật

Một số đề nghị chỉ sử dụng grep -co foothay vì grep -o foo | wc -l.

Đừng.

Phím tắt này sẽ không hoạt động trong mọi trường hợp. Trang Man nói:

-c print a count of matching lines

Sự khác biệt trong các cách tiếp cận này được minh họa dưới đây:

1.

$ echo afoobarfoobar | grep -oc foo
1

Ngay sau khi kết quả phù hợp được tìm thấy trong dòng ( a{foo}barfoobar), việc tìm kiếm sẽ dừng lại. Chỉ có một dòng được kiểm tra và nó phù hợp, vì vậy đầu ra là 1. Trên thực tế -ođược bỏ qua ở đây và bạn chỉ có thể sử dụng grep -cthay thế.

2.

$ echo afoobarfoobar | grep -o foo
foo
foo

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

Hai kết quả phù hợp được tìm thấy trong dòng ( a{foo}bar{foo}bar) bởi vì chúng tôi đã yêu cầu tìm mọi lần xuất hiện ( -o). Mọi điều xảy ra được in trên một dòng riêng biệt, và wc -lchỉ đếm số dòng trong đầu ra.


1
Wow ... nó thực sự đơn giản vậy sao?
jrdioko

1
grep -oc không hoạt động trong trường hợp này. Thử echo afoobarfoobar | grep -oc foo
Paulus

Không có cách nào để làm điều này cho nhiều tệp? Giả sử tôi muốn xem số lần xuất hiện trên mỗi tệp trên một nhóm tệp. Tôi có thể làm điều đó trên mỗi dòng với grep -c *, nhưng không phải theo từng trường hợp.
Keith Tyler

grep -o foo a.txt b.txt | sort | uniq -choạt động tốt (với GNU grep): gist.github.com/hudolejev/81a05791f38cbacfd4de3ee3b44eb4f8
hudolejev

2

Thử cái này:

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

Mẫu vật:

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

Một bài đăng muộn:
Sử dụng mẫu regex tìm kiếm làm Dấu phân cách bản ghi (RS) trong awk
Điều này cho phép regex của bạn kéo dài \ncác dòng được giới hạn (nếu bạn cần).

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

0

Ripgrep , một giải pháp thay thế nhanh chóng cho grep, vừa giới thiệu --count-matchescờ cho phép đếm từng trận đấu trong phiên bản 0.9 (Tôi đang sử dụng ví dụ trên để duy trì sự nhất quán):

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

Theo yêu cầu của OP, ripgrep cũng cho phép mẫu regex ( --regexp <PATTERN>). Ngoài ra, nó có thể in từng (dòng) khớp trên một dòng riêng biệt:

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

-1

Hack chức năng màu của grep và đếm xem nó in ra bao nhiêu thẻ màu:

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
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.