web-dev-qa-db-ja.com

ファイル内のパターンの出現回数をカウントします(同じ行でも)

ファイル内の文字列の出現回数を検索するとき、私は通常以下を使用します:

grep pattern file | wc -l

ただし、grepの動作方法により、これは1行につき1回しか検出されません。文字列が同じ行にあるか異なる行にあるかに関係なく、ファイルに文字列が出現する回数を検索するにはどうすればよいですか?

また、単純な文字列ではなく、正規表現パターンを検索している場合はどうなりますか?どうすればそれらをカウントできますか、さらに良いことに、各マッチを新しい行に印刷できますか?

88
jrdioko

すべての発生をカウントするには、-oを使用します。これを試して:

echo afoobarfoobar | grep -o foo | wc -l

そしてman grepもちろん(:

更新

grep -co fooの代わりにgrep -o foo | wc -lのみを使用することを提案する人もいます。

しないでください。

このショートカットはすべての場合に機能するわけではありません。マニュアルページは言う:

-c print a count of matching lines

これらのアプローチの違いを以下に示します。

1。

$ echo afoobarfoobar | grep -oc foo
1

一致が見つかるとすぐに行内a{foo}barfoobar)検索が停止します。 1行のみがチェックされ、一致したため、出力は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)を見つけるよう明示的に要求したため、2つの一致が行(-o)で見つかりました。すべての出現は個別の行に出力され、wc -lは出力の行数をカウントするだけです。

149
hudolejev

これを試して:

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]
2

遅ればせながらの投稿:
検索正規表現パターンをawkのレコード区切り文字(RS)として使用する
これにより、正規表現を\nで区切られた行に広げることができます(必要な場合)。

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

Ripgrep は、grepの高速な代替手段であり、カウントを許可する--count-matchesフラグを導入したばかりですeachmatch inバージョン0.9(一貫性を保つために上記の例を使用しています):

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

OPが尋ねたように、ripgrepは正規表現パターンも許可します(--regexp <PATTERN>)。また、各(行)マッチを別々の行に出力できます:

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