grepを使用して発生の総数を数える


215

grep -cファイル内で文字列が何回出現するかを見つけるのに役立ちますが、各出現を1行に1回だけカウントします。行ごとに複数の発生をカウントする方法は?

私はよりエレガントなものを探しています:

perl -e '$_ = <>; print scalar ( () = m/needle/g ), "\n"'

4
grepが指定されていることは知っていますが、使用している人にとってackは、答えは単純ack -ch <pattern>です。
カイルストランド

回答:


302

grep -oは一致を出力するだけで、行は無視します。wcそれらを数えることができます:

grep -o 'needle' file | wc -l

これは「針」または「多針」にも一致します。
単一の単語のみ:

grep -o '\bneedle\B' file | wc -l
# or:
grep -o '\<needle\>' file | wc -l

6
これにはGNU grep(Linux、Cygwin、FreeBSD、OSX)が必要であることに注意してください。
ジル

@wag ここで魔法\b\Bは何ですか?
オタク14年

6
@Geek \ bは単語の境界に一致し、\ Bは単語の境界に一致しません。上記の答えは、両端で\ bを使用した場合により正確です。
リアム

1
1行あたりの出現回数については、grep -nオプションとuniq -c ... grep -no '\ <needle \>' file | uniq -c
ジェームズウォーレン

@jameswarren uniqは、隣接する同一行のみを削除します。重複が常にすぐ隣接するかどうかがまだわからない場合は、sortフィードする前にする必要がありuniqます。
トリプリー

16

あなたは(たまに他の場所で常にLinuxやCygwinの上、)GNU grepのを持っている場合は、次のことができますから、出力ラインを数えますgrep -ogrep -o needle | wc -l

Perlを使用して、(修正された後でも)あなたよりもエレガントな方法をいくつか紹介します。

perl -lne 'END {print $c} map ++$c, /needle/g'
perl -lne 'END {print $c} $c += s/needle//g'
perl -lne 'END {print $c} ++$c while /needle/g'

POSIXツールのみを使用する場合、可能であれば1つのアプローチは、入力をgrepに渡す前に単一の一致を持つ行に分割することです。たとえば、単語全体を検索する場合、最初にすべての非単語文字を改行に変換します。

# equivalent to grep -ow 'needle' | wc -l
tr -c '[:alnum:]' '[\n*]' | grep -c '^needle$'

そうでない場合、この特定のテキスト処理を行う標準コマンドはないため、sed(マゾの場合)またはawkを使用する必要があります。

awk '{while (match($0, /set/)) {++c; $0=substr($0, RSTART+RLENGTH)}}
     END {print c}'
sed -n -e 's/set/\n&\n/g' -e 's/^/\n/' -e 's/$/\n/' \
       -e 's/\n[^\n]*\n/\n/g' -e 's/^\n//' -e 's/\n$//' \
       -e '/./p' | wc -l

以下はsedand を使用したより簡単なソリューションですgrep。これは、文字列またはブックごとの正規表現でも機能しますが、アンカーパターンでいくつかのコーナーケースで失敗します(たとえば、^needleまたはの2つの出現を検出\bneedleしますneedleneedle)。

sed 's/needle/\n&\n/g' | grep -cx 'needle'

上記のsed置換では、以前\nは改行を意味していたことに注意してください。これはパターン部分では標準ですが、代替テキストでは、移植性のために、バックスラッシュと改行を置き換えます\n


4

私のように、「両方;それぞれ1回だけ」が実際に必要な場合(これは実際には "どちらか; 2回")、それは簡単です:

grep -E "thing1|thing2" -c

そして、出力を確認します2

このアプローチの利点は(1回だけが必要な場合)、簡単にスケーリングできることです。


あなたが実際にそれが一度しか表示されていないことを確認しているのかわかりませんか?探しているのは、これらの単語のいずれかが少なくとも1回存在することです。
スティーブゴア

3

needleフィールドセパレータとしてawkを使用する別のソリューション:

awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'

needle句読点が続くマッチしたい場合、フィールドセパレータをそれに応じて変更してください。

awk -F'^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$' '{c+=NF-1}END{print c}'

または、クラス:[^[:alnum:]]を使用して、すべての非アルファ文字を包含します。


これには、regexpフィールド区切り文字(GNU awkなど)をサポートするawkが必要であることに注意してください。
ジル

1

この例では、ファイルごとの合計数ではなく、行ごとのオカレンス数のみを出力します。それがあなたが望むものであれば、このような何かがうまくいくかもしれません:

perl -nle '$c+=scalar(()=m/needle/g);END{print $c}' 

あなたは正しいです-私の例では、最初の行の出現のみをカウントします。

1

これは私の純粋なbashソリューションです

#!/bin/bash

B=$(for i in $(cat /tmp/a | sort -u); do
echo "$(grep $i /tmp/a | wc -l) $i"
done)

echo "$B" | sort --reverse
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.