IPアドレスでソートされたログファイルがあります。一意の各IPアドレスの発生数を調べたいのですが。どうすればbashでこれを行うことができますか?おそらく、次のように、IPの横に発生数をリストします。
5.135.134.16 count: 5
13.57.220.172: count 30
18.206.226 count:2
等々。
ログのサンプルは次のとおりです。
5.135.134.16 - - [23/Mar/2019:08:42:54 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
5.135.134.16 - - [23/Mar/2019:08:42:55 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
5.135.134.16 - - [23/Mar/2019:08:42:55 -0400] "POST /wp-login.php HTTP/1.1" 200 3836 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
5.135.134.16 - - [23/Mar/2019:08:42:55 -0400] "POST /wp-login.php HTTP/1.1" 200 3988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
5.135.134.16 - - [23/Mar/2019:08:42:56 -0400] "POST /xmlrpc.php HTTP/1.1" 200 413 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:05 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:06 -0400] "POST /wp-login.php HTTP/1.1" 200 3985 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:07 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:08 -0400] "POST /wp-login.php HTTP/1.1" 200 3833 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:09 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:11 -0400] "POST /wp-login.php HTTP/1.1" 200 3836 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:12 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:15 -0400] "POST /wp-login.php HTTP/1.1" 200 3837 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:17 -0400] "POST /xmlrpc.php HTTP/1.1" 200 413 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.233.99 - - [23/Mar/2019:04:17:45 -0400] "GET / HTTP/1.1" 200 25160 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36"
18.206.226.75 - - [23/Mar/2019:21:58:07 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "https://www.google.com/url?3a622303df89920683e4421b2cf28977" "Mozilla/5.0 (Windows NT 6.2; rv:33.0) Gecko/20100101 Firefox/33.0"
18.206.226.75 - - [23/Mar/2019:21:58:07 -0400] "POST /wp-login.php HTTP/1.1" 200 3988 "https://www.google.com/url?3a622303df89920683e4421b2cf28977" "Mozilla/5.0 (Windows NT 6.2; rv:33.0) Gecko/20100101 Firefox/33.0"
18.213.10.181 - - [23/Mar/2019:14:45:42 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
18.213.10.181 - - [23/Mar/2019:14:45:42 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
18.213.10.181 - - [23/Mar/2019:14:45:42 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
アドレスのリストにgrep
とuniq
を使用し、それらをループし、カウントにgrep
を再度使用できます。
for i in $(<log grep -o '^[^ ]*' | uniq); do
printf '%s count %d\n' "$i" $(<log grep -c "$i")
done
grep -o '^[^ ]*'
は、各文字の先頭(^
)から最初のスペースまですべての文字を出力します。uniq
は繰り返される行を削除し、IPアドレスのリストを残します。コマンド置換のおかげで、for
ループはこのリストをループし、現在処理されているIPに続いて「count」とcountを出力します。後者はgrep -c
によって計算され、少なくとも1回一致する行の数をカウントします。
$ for i in $(<log grep -o '^[^ ]*'|uniq);do printf '%s count %d\n' "$i" $(<log grep -c "$i");done
5.135.134.16 count 5
13.57.220.172 count 9
13.57.233.99 count 1
18.206.226.75 count 2
18.213.10.181 count 3
cut
およびuniq
ツールを使用できます。
cut -d ' ' -f1 test.txt | uniq -c
5 5.135.134.16
9 13.57.220.172
1 13.57.233.99
2 18.206.226.75
3 18.213.10.181
説明 :
cut -d ' ' -f1
:最初のフィールド(IPアドレス)を抽出しますuniq -c
:繰り返し行を報告し、発生数を表示します考えられる解決策の1つを次に示します。
_IN_FILE="file.log"
for IP in $(awk '{print $1}' "$IN_FILE" | sort -u)
do
echo -en "${IP}\tcount: "
grep -c "$IP" "$IN_FILE"
done
_
file.log
_を実際のファイル名に置き換えます。$(awk '{print $1}' "$IN_FILE" | sort -u)
は、最初の列の一意の値のリストを提供します。grep -c
_は、ファイル内のこれらの各値をカウントします。_$ IN_FILE="file.log"; for IP in $(awk '{print $1}' "$IN_FILE" | sort -u); do echo -en "${IP}\tcount: "; grep -c "$IP" "$IN_FILE"; done
13.57.220.172 count: 9
13.57.233.99 count: 1
18.206.226.75 count: 2
18.213.10.181 count: 3
5.135.134.16 count: 5
_
いくつかのPerl:
$ Perl -lae '$k{$F[0]}++; }{ print "$_ count: $k{$_}" for keys(%k)' log
13.57.233.99 count: 1
18.206.226.75 count: 2
13.57.220.172 count: 9
5.135.134.16 count: 5
18.213.10.181 count: 3
これは Steeldriverのawkアプローチ と同じアイデアですが、Perlです。 -a
を指定すると、Perlは各入力行を自動的に配列@F
に分割します。配列の最初の要素(IP)は$F[0]
です。したがって、$k{$F[0]}++
はハッシュ%k
を作成します。そのキーはIPであり、その値は各IPが表示された回数です。 }{
は、「すべての入力を処理した後、最後に残りを実行する」というファンキーなperlspeakです。したがって、最後に、スクリプトはハッシュのキーを反復処理し、現在のキー($_
)とその値($k{$_}
)を出力します。
そして、人々がPerlが不可解な落書きのように見えるスクリプトを書くことをあなたに強制するとは思わないので、これはあまり凝縮されていない形で同じことです:
Perl -e '
while (my $line=<STDIN>){
@fields = split(/ /, $line);
$ip = $fields[0];
$counts{$ip}++;
}
foreach $ip (keys(%counts)){
print "$ip count: $counts{$ip}\n"
}' < log
多分これはOPが望むものではありません。ただし、IPアドレスの長さが15文字に制限されることがわかっている場合は、uniq
コマンドのみを使用して、巨大なログファイルから一意のIPを含むカウントをより迅速に表示できます。
$ uniq -w 15 -c log
5 5.135.134.16 - - [23/Mar/2019:08:42:54 -0400] ...
9 13.57.220.172 - - [23/Mar/2019:11:01:05 -0400] ...
1 13.57.233.99 - - [23/Mar/2019:04:17:45 -0400] ...
2 18.206.226.75 - - [23/Mar/2019:21:58:07 -0400] ...
3 18.213.10.181 - - [23/Mar/2019:14:45:42 -0400] ...
オプション:
-w N
はN
文字以下の行を比較します
-c
は、オカレンスの数を行の前に付けます
または、正確にフォーマットされた出力の場合、awk
(IPV6アドレスでも機能するはずです)、ymmvを好みます。
$ awk 'NF { print $1 }' log | sort -h | uniq -c | awk '{printf "%s count: %d\n", $2,$1 }'
5.135.134.16 count: 5
13.57.220.172 count: 9
13.57.233.99 count: 1
18.206.226.75 count: 2
18.213.10.181 count: 3
uniq
は、隣接していない場合、入力ファイル内の繰り返される行を検出しないため、ファイルをsort
する必要がある場合があることに注意してください。
FWIW、Python 3:
from collections import Counter
with open('sample.log') as file:
counts = Counter(line.split()[0] for line in file)
for ip_address, count in counts.items():
print('%-15s count: %d' % (ip_address, count))
出力:
13.57.233.99 count: 1
18.213.10.181 count: 3
5.135.134.16 count: 5
18.206.226.75 count: 2
13.57.220.172 count: 9
cut -f1 -d- my.log | sort | uniq -c
説明:my.logの最初のフィールドをダッシュで分割します-
と並べ替えます。 uniq
にはソートされた入力が必要です。 -c
は、発生をカウントするように指示します。