Hitung jumlah kemunculan pola dalam file (bahkan pada baris yang sama)

94

Saat mencari jumlah kemunculan string dalam sebuah file, saya biasanya menggunakan:

grep pattern file | wc -l

Namun, ini hanya menemukan satu kemunculan per baris, karena cara kerja grep. Bagaimana saya bisa mencari berapa kali string muncul dalam sebuah file, terlepas dari apakah mereka berada pada baris yang sama atau berbeda?

Juga, bagaimana jika saya mencari pola regex, bukan string sederhana? Bagaimana cara menghitungnya, atau, bahkan lebih baik, mencetak setiap kecocokan pada baris baru?

jrdioko
sumber

Jawaban:

157

Untuk menghitung semua kejadian, gunakan -o. Coba ini:

echo afoobarfoobar | grep -o foo | wc -l

Dan man greptentu saja (:

Memperbarui

Beberapa menyarankan untuk menggunakan saja grep -co foodaripada grep -o foo | wc -l.

Jangan.

Pintasan ini tidak akan berfungsi di semua kasus. Halaman manual mengatakan:

-c print a count of matching lines

Perbedaan dalam pendekatan ini diilustrasikan di bawah ini:

1.

$ echo afoobarfoobar | grep -oc foo
1

Segera setelah kecocokan ditemukan di baris ( a{foo}barfoobar) pencarian berhenti. Hanya satu baris yang diperiksa dan cocok, jadi hasilnya adalah 1. Sebenarnya -odiabaikan di sini dan Anda bisa menggunakan grep -csaja.

2.

$ echo afoobarfoobar | grep -o foo
foo
foo

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

Dua kecocokan ditemukan di baris ( a{foo}bar{foo}bar) karena kita secara eksplisit diminta untuk menemukan setiap kemunculan ( -o). Setiap kemunculan dicetak pada baris terpisah, dan wc -lhanya menghitung jumlah baris dalam output.

hudolejev
sumber
1
Wow ... benarkah sesederhana itu?
jrdioko
1
grep -oc tidak berfungsi dalam kasus ini. Coba echo afoobarfoobar | grep -oc foo
Paulus
Apakah tidak ada cara untuk melakukan ini untuk banyak file? Katakanlah saya ingin melihat jumlah kejadian per file pada satu set file. Saya bisa melakukannya per baris dengan grep -c *, tetapi tidak per baris .
Keith Tyler
grep -o foo a.txt b.txt | sort | uniq -cberfungsi dengan baik (dengan GNU grep): gist.github.com/hudolejev/81a05791f38cbacfd4de3ee3b44eb4f8
hudolejev
2

Coba ini:

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

Sampel:

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]
IBrewThereforeIAm
sumber
1

Posting terlambat:
Gunakan pola regex pencarian sebagai Record Separator (RS) di awk
Ini memungkinkan ekspresi reguler Anda menjangkau \nbaris-baris yang dibatasi (jika Anda membutuhkannya).

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

Ripgrep , yang merupakan alternatif cepat untuk grep, baru saja memperkenalkan --count-matchesbendera yang memungkinkan penghitungan setiap pertandingan di versi 0.9 (Saya menggunakan contoh di atas untuk tetap konsisten):

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

Seperti yang diminta oleh OP, ripgrep memungkinkan pola regex juga ( --regexp <PATTERN>). Juga dapat mencetak setiap (baris) kecocokan pada baris terpisah:

> echo -e "line1foo\nline2afoobarfoobar" | rg foo
line1foo
line2afoobarfoobar
Sebastian Müller
sumber
-1

Retas fungsi warna grep, dan hitung berapa banyak tag warna yang dicetaknya:

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
Shizzmo
sumber