スポンサーリンク
近年の労働環境における大きなテーマである働き方改革。
まあ色々な捉え方・進め方があるわけですが、業務効率化という観点で言えばエンジニアに求められるものは大きいかと思います。
ということで今回は日常業務の効率化に効く(と思う)awkの使いこなし方を解説したいと思います。
まあ若干タイトル詐欺な感じも否めませんが、awkを10倍くらい使いこなして業務を効率化しましょう!ということで読んで頂ければ幸いです。
こちらの記事にわかりやすくまとめました。→ awkって何?何ができるの?をできる限りわかりやすく伝えたい をお読みください。
awkをより使いこなすためには以下3点を知る必要があります。
今回はこの3点にフォーカスして説明していきます。
awkの経験値が浅い方は、awkの文法は
awk '{ print カラム番号 }' ファイル名
だと思っている方が多いのではないでしょうか。
これも間違いではないのですが、実際にはもっと色々指定できて、
awk 'BEGIN{ 前処理 }判定条件{ メイン処理 }END{ 後処理 }' ファイル名
のように書くことができます。
(このうち、いくつかを省略して書くことができ、省略すると最初の例のような文法になります)
百聞は一見にしかず、実際に実行してみましょう。
こう言うファイルがあったとして、
$ cat file.txt
本文だよ
以下のようにコマンドを実行すると
awk 'BEGIN{print "前処理"}{print $0}END{print "後処理"}' file.txt
こういった結果になります。
前処理
本文だよ
後処理
これだけを見てもよくわからないと思うので、詳しく説明していきます。
先程の文法をわかりやすく書き直すと、以下のようになります。
色で分けているのが処理の区切りになっています。
私が思うに、 awkの分かり辛いところは、このブロックを区切る文字が無いところ だと思います。
(他の言語であれば、 ;
とか ,
とか入りそうなところ)
さて、先程少し書きましたが、この文法のうち、
は省略することができます。それらを省略すると
awk '{メイン処理}' ファイル名
となり、普段見慣れた文法になるはずです。
awkは基本的にファイル or 標準入力から行を読み込み処理を行いますが、入力を読み込む前後(1行目を読み込む前、最終行を読み込んだ後)にも処理を入れることができます。
それが、BEGIN
と END
の2つの句です。
これを使うことで、例えば ファイル中のある数値カウントし、合計値・平均値を算出する
といった用途でとても役に立ちます。
以下のようなファイルがあったとします。
$ cat score.txt
----------------
team1, Taro, 98
team2, Hanako, 73
team1, Ichiro, 87
team2, Shinichi, 76
team1, Ken, 85
team2, Dai, 69
----------------
このファイルから team1のメンバーの合計点・平均点を算出
してみます。
コマンド
$ grep "team1" score.txt | awk 'BEGIN{sum=0;count=0}{sum+=$3;count++}END{print "合計点: " sum " 平均点: " sum/count}'
結果
合計点: 270 平均点: 90
いかがでしょうか。少しわかりづらいかもしれませんので以下解説していきます。
まず前提として最初の grepコマンド
により、awkに渡される入力は以下になります。
team1, Taro, 98
team1, Ichiro, 87
team1, Ken, 85
これを受け取ったawkは以下の処理を行います。
青字の部分が BEGIN句 で指定した部分、 赤字が 各行に対して実行されるメイン処理 、緑字が END句 で指定した処理となります。
このように、 BEGIN
は 入力を読み込む前の処理 、END
は 全ての行を読み込んだ後に実行する処理 を定義できます。
3つ目は判定条件の書き方です。これもなかなか分かりづらいので丁寧に説明します。
まず先程の例をもう一度見てみると、最初に grepコマンド
で team1の行を抜き出している
ことが分かります。
$ grep "team1" score.txt | awk 'BEGIN{sum=0;count=0}{sum+=$3;count++}END{print "合計点: " sum " 平均点: " sum/count}'
実はこの部分をawkだけで書くことができます。その際に使うのが判定条件文です。
ということで、先程の例をawkだけに書き換えてみます。
$ awk 'BEGIN{sum=0;count=0}$1=="team1,"{sum+=$3;count++}END{print "合計点: " sum " 平均点: " sum/count}' score.txt
変わった点はBEGIN句の直後に $1=="team1,"
という文が入っている点です。
この文は、 $1が "team1," に一致した場合のみ、メイン処理を実行する
という意味です。
この文を入れることにより、grepのように 一致する行だけを抜きだす
ということが可能になります。
ちなみに、この条件分岐を使えば、 最初の行以外に処理を行う
ということも容易に実現できます。
$ awk 'NR>1{ print }' score.txt
team2, Hanako, 73
team1, Ichiro, 87
team2, Shinichi, 76
team1, Ken, 85
team2, Dai, 69
NR
というのは 読み込んだ行の番号(1からインクリメントされていく)ですので、 NR>1
という書き方で 2行目以降 という意味になります。
今回記載した内容は他のコマンドで代替できることが多いのは事実ですが、他のコマンドとパイプで多段につなぐよりも入力の走査回数が少なくなるため高速に動作するはずです。
これは数ギガバイトというファイルに処理をする時には明確な差になります。
ということで、awkをより使いこなすためのコツを書きました。
お役に立てれば幸いです。
スポンサーリンク