Bashスクリプト:ファイル内の一意の行を数える


129

状況:

数時間のネットワークキャプチャからのIPアドレスとポートを含む大きなファイル(数百万行)があり、1行に1つのIP /ポートがあります。行は次の形式です。

ip.ad.dre.ss[:port]

望ましい結果:

ロギング中に受け取ったパケットごとにエントリがあるため、重複したアドレスが多数あります。これをある形式のシェルスクリプトで実行できるようにしたいのですが、それをフォーマットの行に減らすことができます

ip.ad.dre.ss[:port] count

ここで、countその特定のアドレス(およびポート)の発生数です。特別な作業を行う必要はありません。異なるポートを異なるアドレスとして扱います。

これまでのところ、私はこのコマンドを使用して、ログファイルからすべてのIPアドレスをスクレイピングしています。

grep -o -E [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(:[0-9]+)? ip_traffic-1.log > ips.txt

それから、私はかなり単純な正規表現を使用して、自分のアドレスから送信されたすべてのIPアドレス(私は気にしません)をこすり落とすことができます

次に、以下を使用して一意のエントリを抽出できます。

sort -u ips.txt > intermediate.txt

どうやってソートで行数を集計できるのかわかりません。

回答:


303

uniqコマンドを使用して、並べ替えられた繰り返し行の数を取得できます。

sort ips.txt | uniq -c

最も頻繁に結果を表示するには(Peter Jaricに感謝):

sort ips.txt | uniq -c | sort -bgr

10
Iどのような-bgrのニーモニックのように見える偶然にbigger私たちが一番上に望むものです。
dwanderson

1
あなたのための小さな機能として、.bashrcまたは.bash_aliasesファイル:function countuniquelines () { sort "$1" | uniq -c | sort -bgr; }。までお電話くださいcountuniquelines myfile.txt
ヨハン

なぜかわからないsort -nr
ナキロン

5

一意の行の総数をカウントするには(つまり、重複行を考慮しない)uniqwc次のようにAwkを使用できます。

sort ips.txt | uniq | wc -l
awk '!seen[$0]++' ips.txt | wc -l

Awkの配列は結合的であるため、ソートよりも少し速く実行できます。

テキストファイルを生成しています:

$  for i in {1..100000}; do echo $RANDOM; done > random.txt
$ time sort random.txt | uniq | wc -l
31175

real    0m1.193s
user    0m0.701s
sys     0m0.388s

$ time awk '!seen[$0]++' random.txt | wc -l
31175

real    0m0.675s
user    0m0.108s
sys     0m0.171s

面白い。巨大なデータセットのためにかなりの違いになるかもしれない
WUG

1

これは、繰り返される行の数を取得し、それらを最も頻度の低いものから最も頻度の高いものまできれいに印刷する最も速い方法です。

awk '{!seen[$0]++}END{for (i in seen) print seen[i], i}' ips.txt | sort -n

パフォーマンスを気にせず、覚えやすいものにしたい場合は、次のコマンドを実行します。

sort ips.txt | uniq -c | sort -n

PS:

sort -nは、フィールドを数値として解析します。これは、カウントを使用してソートしているためです。


で印刷するだけなので、ここ!{!seen[$0]++}はin は冗長ですEND
アミール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.