SadServers解説 Easy No.2 「IPアドレスを数えてください」
問題概要
問題URL
シナリオ
IPアドレスを数えてください
問題詳細
/home/admin/access.log は Web サーバのアクセスログです。
このファイルは 1 行が 1 回の HTTP リクエストで、各行の先頭列にはリクエスト元の IP アドレスが入っています。
このログの中で、最も多く登場する IP アドレスを見つけて、/home/admin/highestip.txt に書き込みます。例えば回答が "1.2.3.4" の場合は、echo "1.2.3.4" > /home/admin/highestip.txt を実行します。
同率はなく、最多の IP アドレスは 1 つだけです。正解の IP アドレスは access.log に 482 回出現します。
解決判定
答えを/home/admin/highestip.txtに記載してください。例えば回答が"1.2.3.4"の場合は、以下のコマンドを実行してください。
echo "1.2.3.4" > /home/admin/highestip.txt
sha1sum /home/admin/highestip.txt の結果は 6ef426c40652babc0d081d438b9f353709008e93 になります。
問題解決の方針
【表示する】
この問題は、アクセスログの先頭列に並んでいる IP アドレスを集計して、最も多く現れる値を見つける問題です。
具体的な解決の段取りを表示する
- まずログの形式を見て、先頭列が本当に IP アドレスか確認する。
- 先頭列だけを取り出して、集計対象を IP アドレスの一覧に絞る。
- 同じ IP アドレスを数えられる形に整えて、出現回数を集計する。
- 件数が最大の IP アドレスを特定する。
ヒント
オリジナルヒント
ヒント1
最初に、ログの先頭に IP アドレスがあることを確認します。
実行コマンド
ログの先頭部分を見て、各行の最初に IP アドレスがあるか確認します。
~$ head /home/admin/access.log
83.149.9.216 - - [17/May/2015:10:05:03 +0000] "GET /presentations/logstash-monitorama-2013/images/kibana-search.png HTTP/1.1" 200 203023 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"
83.149.9.216 - - [17/May/2015:10:05:43 +0000] "GET /presentations/logstash-monitorama-2013/images/kibana-dashboard3.png HTTP/1.1" 200 171717 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"
83.149.9.216 - - [17/May/2015:10:05:47 +0000] "GET /presentations/logstash-monitorama-2013/plugin/highlight/highlight.js HTTP/1.1" 200 26185 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"
...
ヒント2
先頭列が IP アドレスだと分かったら、次はその列だけを抜き出します。
この問題では空白区切りの 1 列目を取りたいので、cut を素直に使えます。
実行コマンド
1 列目だけを表示して、IP アドレスだけの一覧になるか確認します。
$ cut -d' ' -f1 /home/admin/access.log | head
83.149.9.216
83.149.9.216
83.149.9.216
83.149.9.216
83.149.9.216
83.149.9.216
83.149.9.216
83.149.9.216
83.149.9.216
83.149.9.216
ヒント3
IP アドレスの一覧ができたら、同じ値を数えます。
ただし uniq -c は、同じ行が連続していないと正しく数えられません。
そのため、先に並べ替えてから件数を数えます。
実行コマンド
IP アドレスだけを取り出し、並べ替えてから件数を集計します。
$ cut -d' ' -f1 /home/admin/access.log | sort | uniq -c | head
6 1.22.35.226
6 100.2.4.116
84 100.43.83.137
33 101.119.18.35
3 101.199.108.50
1 101.226.168.196
1 101.226.168.198
2 101.226.33.222
4 103.245.44.13
1 103.247.192.5
ヒント4
件数一覧ができたら、最後に「件数が最大の行」を取り出します。
実行コマンド
件数の多い順に並べて最上位を確認します。
件数の大小で並べ替えるために、再度 sort を使います。-n で数値として比較し、-r で大きい順に並べます。
$ cut -d' ' -f1 /home/admin/access.log | sort | uniq -c | sort -nr | head
482 66.249.73.135
364 46.105.14.53
357 130.237.218.86
273 75.97.9.59
113 50.16.19.13
102 209.85.238.199
99 68.180.224.225
84 100.43.83.137
83 208.115.111.72
82 198.46.149.143
この出力から、最も多く登場する IP アドレスは 66.249.73.135 だと読み取れます。答えをファイルに書き込み、sha1sum で確認します。
$ echo "66.249.73.135" > /home/admin/highestip.txt
$ sha1sum /home/admin/highestip.txt
6ef426c40652babc0d081d438b9f353709008e93 /home/admin/highestip.txt
SadServers公式ヒント(翻訳)
ヒント1
ファイルの 1 列目、つまり IP アドレスを取り出します。
awk '{print $1}' access.log や、空白を区切り文字にした cut を使えます。
フィルタが正しく動いているか確認するために、途中で head や tail を付けるとよいでしょう。
ヒント2
前の手順で取り出した IP アドレスを並べ替えて、同じ IP アドレスがまとまるようにします。
ヒント3
次に uniq -c で件数を数えます。
ここまでで、awk '{print $1}' access.log | sort | uniq -c になります。
ヒント4
最後に、その結果を sort で並べ替えます。
昇順なら最後の行を tail -1 で取り出し、逆順なら sort -r で先頭を取れます。
たとえば awk '{print $1}' access.log | sort | uniq -c | sort -r | head -1 のようにできます。
参考
今回は cut を使う方針で進めました。一方で、公式ヒントは awk を中心に説明しています。awk は cut より記述が複雑ですが、その分できることも多く、列の加工や条件付き集計など柔軟に対応できます。cut で解決できたら、次は awk で同じことができるか試してみてもよいかもしれません。
「いきなり問題を解き始めても調べるばかりになってしまう…」 「やりたいことが分かっても、コマンドが分からない…」 という方は、下記の記事でLinuxのコマンドを復習してから、SadServersの問題に取り掛かってみてはいかがでしょうか。
問題一覧はこちら
Discussion