Bir dosyadaki bir desenin oluşum sayısını sayın (aynı satırda bile)


94

Bir dosyada bir dizenin oluşum sayısını ararken genellikle şunu kullanırım:

grep pattern file | wc -l

Bununla birlikte, grep'in çalışma şekli nedeniyle bu, satır başına yalnızca bir oluşum bulur. Aynı veya farklı satırlarda olup olmadıklarına bakılmaksızın, bir dizenin bir dosyada kaç kez göründüğünü nasıl arayabilirim?

Ayrıca, basit bir dize değil, bir normal ifade kalıbı arıyorsam? Bunları nasıl sayabilirim veya daha da iyisi her maçı yeni bir satıra yazdırabilirim?

Yanıtlar:


158

Tüm tekrarları saymak için kullanın -o. Bunu dene:

echo afoobarfoobar | grep -o foo | wc -l

Ve man greptabii ki (:

Güncelleme

Bazıları grep -co foobunun yerine kullanmayı önerir grep -o foo | wc -l.

Yapma.

Bu kısayol her durumda çalışmayacaktır. Adam sayfası diyor ki:

-c print a count of matching lines

Bu yaklaşımlardaki farklılık aşağıda gösterilmektedir:

1.

$ echo afoobarfoobar | grep -oc foo
1

En kısa sürede eşleşme bulunduğunda olarak hattında ( a{foo}barfoobar) arama durur. Yalnızca bir satır kontrol edildi ve eşleşti, yani çıktı 1. Aslında -oburada görmezden gelinir ve grep -cbunun yerine kullanabilirsiniz .

2.

$ echo afoobarfoobar | grep -o foo
foo
foo

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

( a{foo}bar{foo}bar) Satırında iki eşleşme bulunur çünkü açıkça her bir tekrarı bulmamız istenmiştir ( -o). Her olay ayrı bir satıra yazdırılır ve wc -lyalnızca çıktıdaki satır sayısını sayar.


1
Vay be ... gerçekten bu kadar basit mi?
jrdioko

1
grep -oc bu durumda çalışmaz. Echo afoobarfoobar'ı deneyin | grep -oc foo
Paulus

Bunu birden çok dosya için yapmanın bir yolu yok mu? Diyelim ki bir dosya kümesinde dosya başına oluşum sayısını görmek istiyorum. Grep -c * ile satır başına yapabilirim , ancak örnek başına değil.
Keith Tyler

grep -o foo a.txt b.txt | sort | uniq -c: Sadece (GNU grep ile) para cezası çalışır gist.github.com/hudolejev/81a05791f38cbacfd4de3ee3b44eb4f8
hudolejev

2

Bunu dene:

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

Örneklem:

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

Gecikmiş bir gönderi:
Arama normal ifade kalıbını içinde Kayıt Ayırıcı (RS) olarak kullanın awk
Bu, normal \nifadenizin-sınırlı satırlara (gerekirse) yayılmasına olanak tanır .

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

0

Grep'e hızlı bir alternatif olan Ripgrep , 0.9 sürümünde her bir eşleşmeyi --count-matchessaymaya izin veren bayrağı tanıttı (tutarlı kalmak için yukarıdaki örneği kullanıyorum):

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

OP tarafından sorulduğu gibi, ripgrep düzenli ifade kalıbına da ( --regexp <PATTERN>) izin verir . Ayrıca her (satır) eşleşmeyi ayrı bir satıra yazdırabilir:

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

-1

Grep'in renk işlevini kırın ve kaç tane renk etiketi yazdırdığını sayın:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.