www.morihi-soc.net

セキュリティの話題を中心に取扱中

cut と awk はどちらが高速なのか

どうもハニーポッターです.

先日,社内の勉強会に参加しているときに,「Web サーバをのログを調査するときは,膨大な量のデータから欲しい情報を抽出して効率よく解析しなければならない」という話がありました.

抽出したい情報とは,たとえばアクセスのあったファイル名やアクセス元 IP アドレスなどですが,発表者の方は awk コマンドを使って抽出されていました.

で,ここで1つの素朴な疑問が.
「1行データの中から,特定のフィールドを抽出するだけなら awk コマンド使わなくてもよくね? cut コマンドで十分じゃね?」と.

疑問は検証しなければいけないので「大量データから情報を抽出するには cut コマンドと awk コマンドのどちらが高速か?」を調べてみました.


※この記事は「適材適所でコマンドを使うべきだ」というのが趣旨ですので,決してきのこ・たけのこの争いや,Emacs 対 Vim のエディタ闘争とは関係ありません.

最初に cut コマンドと awk コマンドについておさらいしておきましょう.

cut コマンドは,1行のデータを特定の区切り文字で区切って,特定のフィールドを抽出することができるコマンドです.
参考:【 cut 】 テキスト・ファイルの各行から一部分を取り出す

一方,awk コマンドは,文字列操作をすることができるコマンドで,cut コマンドのように区切り文字を使って,特定のフィールドを抽出することはもちろん,より複雑な文字列操作が可能です.
参考:シェルコマンドを使った処理の効率化は AWKの行(レコード)操作がカギをにぎる 

 

では抽出対象となるデータですが,SSH ハニーポットである Kippo のログ(kippo.log)を使います.(申し訳程度のハニーポット要素)
kippo.log には,攻撃者の IP アドレスや入力したアカウント名・パスワードなどが記録されます.なおログイン後のコンソールログは別ファイルに保存されます.
今回はアカウント名とパスワードの組み合わせを抽出しようと思います.kippo.log には,ログイン試行のログが下記のように記録されます.

2015-03-09 10:05:11+0900 [SSHService ssh-userauth on HoneyPotTransport,134691,***.***.***.***] login attempt [root/rooted] failed

スペース区切りで「日付,時間,[接続情報],login,attempt,[アカウント名とパスワード],ログイン成功・失敗」となります.今回欲しいのは9番目のフィールドのアカウント名とパスワードなので,これを抽出します.

cut コマンドと awk コマンドで区切り文字をスペースとして,9番目のフィールドを抽出する方法は下記の通りです.

cut コマンドの場合
% cut -d’ ‘ -f9 kippo.log

 

awk コマンドの場合
% awk -F’ ‘ ‘{ print $9 }’ kippo.log

 

そして抽出対象の Kippo のログですが,私のハニーポットで収集したデータを使います.また正規化というわけではないですが,ログイン試行の行のみを対象にします.気になる行数ですが・・・

% wc -l kippo.log
3308613

ということで,約330万回の不正なログインの試みを検知しているデータを使います.

このデータに対して上記の cut コマンドと awk コマンドを実行します.一応それぞれ10回試してみて,その平均値を確認します.

計測環境
MacBook Pro(Retina, Mid 2012), Mac OS X(Yosemite), Intel Core i7 2.6GHz, 16GB Memory, SSD

それではさっくりと結果発表です.なお時間の計測には zsh の time コマンドを使っています.

cut コマンド
% for i in {1..10} ; do time cut -d’ ‘ -f9 orig.log > /dev/null ; done
cut -d’ ‘ -f9 orig.log > /dev/null  10.41s user 0.14s system 99% cpu 10.559 total
cut -d’ ‘ -f9 orig.log > /dev/null  10.38s user 0.14s system 99% cpu 10.527 total
cut -d’ ‘ -f9 orig.log > /dev/null  10.36s user 0.14s system 99% cpu 10.505 total
cut -d’ ‘ -f9 orig.log > /dev/null  10.38s user 0.14s system 99% cpu 10.528 total
cut -d’ ‘ -f9 orig.log > /dev/null  10.38s user 0.14s system 99% cpu 10.532 total
cut -d’ ‘ -f9 orig.log > /dev/null  10.33s user 0.14s system 99% cpu 10.476 total
cut -d’ ‘ -f9 orig.log > /dev/null  10.37s user 0.14s system 99% cpu 10.517 total
cut -d’ ‘ -f9 orig.log > /dev/null  10.41s user 0.14s system 99% cpu 10.558 total
cut -d’ ‘ -f9 orig.log > /dev/null  10.34s user 0.14s system 99% cpu 10.483 total
cut -d’ ‘ -f9 orig.log > /dev/null  10.44s user 0.14s system 99% cpu 10.590 total

 

awk コマンド
% for i in {1..10} ; do time awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null ; done
awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null  24.52s user 0.20s system 99% cpu 24.751 total
awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null  24.34s user 0.19s system 99% cpu 24.556 total
awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null  24.45s user 0.20s system 99% cpu 24.676 total
awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null  24.35s user 0.20s system 99% cpu 24.578 total
awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null  24.40s user 0.20s system 99% cpu 24.620 total
awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null  24.31s user 0.19s system 99% cpu 24.520 total
awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null  24.40s user 0.20s system 99% cpu 24.619 total
awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null  24.29s user 0.19s system 99% cpu 24.498 total
awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null  24.25s user 0.19s system 99% cpu 24.465 total
awk -F’ ‘ ‘{ print $9 }’ orig.log > /dev/null  24.37s user 0.19s system 99% cpu 24.586 total

 

total の時間だけを表にまとめます.

cut awk
1回目 10.559 24.751
2回目 10.527 24.556
3回目 10.505 24.676
4回目 10.528 24.578
5回目 10.532 24.620
6回目 10.476 24.520
7回目 10.517 24.619
8回目 10.558 24.498
9回目 10.483 24.465
10回目 10.590 24.586
平均 10.528 24.587

単位:秒

 

びっくりです.なんと単純な抽出だけであれば,cut コマンドの方が awk コマンドよりも2倍以上高速でした.

 

結論

単純な抽出作業には cut コマンドを使うと高速に処理できる.

記事の冒頭にも書きましたが,コマンドは適材適所で使うべきであるというのが趣旨です.
複雑な文字列抽出や,シェル芸のような華麗な処理をする場合には awk コマンドが適している場合もありますので,この記事がコマンド選びの参考になれば幸いです.

 

おまけ

せっかくアカウント名とパスワードの組み合わせを抽出したので,いくつかランキングなどをご紹介しておきます.

・アカウントとパスワードの組み合わせトップ10

root/admin
root/password
root/root
root/q1w2e3
root/12344321
root/a1s2d3f4
root/888888
root/654321
root/z1x2c3v4
root/123654

 

・入力されたパスワードトップ10

admin
password
root
123456
default
888888
qazwsx
qwer1234
qwe123
q1w2e3

 

・意識高い系パスワード(個人的に気になったパスワード)

!!!!!!!!!!
(!が10個.そんなに両指を使って文字を打ちたくないのか・・・)

*************
(*が13個.そんなに文字を(ry)

———————————————
(-が45個.途中で何回-を入力したかわからなくなるんじゃ・・・)

!1@2#3$4%5^6&7*8(9)0
(シフトを押したり押さなかったり・・・)

konnichiwa
(こんにちわ.そこは挨拶じゃなくて,パスワードをいれるところですよ・・・)

ninjaman
(アイエエエエ! ニンジャ!? ニンジャナンデ!?)

love4u
(どうも.loveからはじまるパスワードは結構多い)

youcantseeme
(残念.見えてるんだよな・・・)

p1a2s3s4w5o6r7d8
(逆に入力しづらくないですかね?)

p@$$w0rd
(意識高い)

Written by morihisa

3月 9th, 2015 at 10:50 pm