Help us understand the problem. What is going on with this article?

awkであそぼ

More than 3 years have passed since last update.

awk便利です。おーく。

awkであそぼ

ワンライナー野郎を極めるにはawkは便利ですが、それ以上にも使おうと思えば使えてしまうのがまたニクいところなので紹介します。

とりあえず使ってみよう

テキストのN列目を全て取得
~$ awk '{print $4}' /var/log/apache/access.log
[18/Feb/2016:21:57:17
[18/Feb/2016:21:57:37
[18/Feb/2016:21:57:47
  :

こんなかんじに、ログ等の一定パターンで区切れるテキストデータを入力として、特定の列を抜き取ったり、幾つかピックアップして順番を変えたりするのがよくある使われ方かなと思います。

さらにここから別のコマンドに渡して統計を取るとかもよくある使われ方かなと思います。

Apacheのアクセスログからちゃちゃっと時間別アクセス数を統計する
~$ awk '{print $4}' access.log | cut -d ":" -f 1-2 | sort | uniq -c
     61 [18/Feb/2016:15
     38 [18/Feb/2016:16
     62 [18/Feb/2016:17
     60 [18/Feb/2016:18
     22 [18/Feb/2016:20
    116 [18/Feb/2016:21

よく使いますよね? (ゴリ押し)

セパレータの設定

そのままつかうと一行ずつ空白に分解していいかんじに処理できますが、-F オプションを使えばセパレータをタブ文字やカンマ等を始め、普通の文字列にでも任意のものに変更することができます。

man
-F value       sets the field separator, FS, to value.
いろいろセパる
~$ awk '{print $4}' access.log | awk -F ":" '{print $1" - "$2}' | tail -1
[18/Feb/2016 - 21
~$ awk '{print $4}' access.log | awk -F "/" '{print $1" - "$2}' | tail -1
[18 - Feb
~$ awk '{print $4}' access.log | awk -F "Feb" '{print $1" - "$2}' | tail -1
[18/ - /2016:21:57:47

{}の中は普通のプログラム言語です

{}の中はC言語っぽいかんじの普通によくあるプログラム言語だと思ってもらえればこの中でもいろいろできることにきっとキミは気づくはず。

printの代わりにprintfを使ってみる
~$ awk '{print $4}' access.log | ¥
   awk -F ":" '{printf "%05d\n", $4}' | tail -2
00037
00047
計算する
~$ awk '{print $4}' access.log | ¥
   awk -F ":" '{print $2"+"$3"+"$4"="$2+$3+$4}' | tail -2
21+57+37=115
21+57+47=125

変数を使い倒す

$1 とか使ってるのもトドのつまりは変数です。既存の変数を変更することもできるし自分で好きな変数を作ることもできます。

変数を使う

変数をつくる
~$ awk '{print $4}' access.log | ¥
   awk -F ":" '{sum=$2+$3+$4; print sum}' | tail -2
115
125
$1とかを変えちゃう
~$ awk '{print $4}' access.log | ¥
   awk -F ":" '{$4+=100; print $4}' | tail -2
137
147

さらにはコマンドラインから変数を渡すこともできます。

man
-v var=value   assigns value to program variable var.
~$ awk '{print $4}' access.log | ¥
   awk -F ":" -v OFFSET=300 '{$4 += OFFSET; print $4}' | tail -2
337
347

組み込み変数

調べたら結構いっぱいあったんですが、自動でセットされている変数でよく使えるものは以下の2つくらいかなと思います。

  • NF ... 現在の行のフィールド数
  • NR ... 現在の行数

ちょっとフォーマット崩れててデコボコしたテキストでも最後のフィールドを取ってきたいよ!ってときは {print $NF} みたいな使い方をすれば取得できますし、NR を使えば awk でいろいろしつつ cat -n みたいなことも一緒にできたりします。

ていうかそもそも入力行を全部処理するコマンドじゃないんで...

manをよく見ると詳しい使い方が書いてあったり。

man(適宜改行してます)
   1. Program structure
       An AWK program is a sequence of pattern {action} pairs and user function definitions.

       A pattern can be:
              BEGIN
              END
              expression
              expression , expression

       One, but not both, of pattern {action} can be omitted.
       If {action} is omitted it is implicitly { print }.
       If pattern is omitted, then it is implicitly matched.
       BEGIN and END patterns require an action.
  • awkっていうのはパターンとアクションのペアとユーザ関数から成っているんだぜ
  • でもパターンかアクションはどっちか省略することもできるよ
  • アクションが省略されたら { print } って書いたことといっしょだよ
  • パターンが省略されたら暗黙的にマッチするぜ!(直訳)
  • でもBEGINとENDの時はちゃんとアクション書いてね

{}で今まで僕たちが書いてきたのはパターンを省略した形で、全部にマッチする意味でした。パターンを指定すると、条件に当てはまった行のみを処理することができます。

パターンを利用する

例えば、アクセスログをChromeに絞ろうとしたら、正規表現を利用して絞り込むことができます。

~$ awk '$0~/Chrome/{print}' access.log
# $0~ は省略可能
~$ awk '/Chrome/{print}' access.log
# ついでに {print} も省略可能
~$ awk '/Chrome/' access.log

これだけだとgrepをかませただけなのと変わらないですが・・。もっと細かく指定するなら Chrome かつ ステータスコードが404 っていうのを出そうしたら、

~$ awk '($9~/^404$/ && /Chrome/)' access.log

ってな風に書くこともできます。

パターンを複数利用する

パターン{アクション} のペアは何個でもかけるので、例えば ステータスコードが404の時は時間を出して、200のときはメソッド名を出す というサンプルにしては無意味すぎることをしようとしたら、

~$ awk '($9~/^404$/){print $9" "$4} ($9~/^200$/){print $9" "$6}' access.log
200 "GET
200 "GET
404 [18/Feb/2016:21:45:23
200 "GET
200 "GET

みたいな芸当もできてしまいます。

この辺までくるともはやワンライナーレベルじゃなくね?っていう疑問につながりますが、それがawk沼への第一歩になります。まて次号!

bami3
イカ娘スキーです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした