mainvisual

1977年、C言語は生まれた直後にawkというスクリプト言語が生まれました。 そんなに昔からあるのに廃れることのない技術となっているのには、 シンプルな言語仕様とテキストを処理する場面で十分な実用性があるからだと思いっています。

awkを使い始めた人がに触れることで、その操作性や合理性に感動し、 複雑な表形式ファイルに対して全く苦痛がなくなり、 間違いなく幸せになると思います。

ぜひ、awkの世界に足を踏み入れて、体感をしてみてください。

awkの使い方

「awk 使い方」と調べると、いい記事が沢山ヒットしますので、 この記事で今更語る必要はないと思います。 ですが、awkについて知りたくて、 初めてこの記事を訪れてくれた人もいると思うので、 僕がおすすめする記事や本をいくつか紹介したいと思います。

【記事紹介1】なるべく書かないawkの使い方Add Star

awkについて全体を網羅したいと思うのであれば、 現時点でネット記事ではこれ一択だと思います。 awkが処理を行なう順番、ハマりどころ、使いドコロ、grepとの決定的な違いなど、 知りたい内容がほぼほぼ書いてあります。

ただ、具体的な使い方には書いてある部分が乏しいので、 他の記事を見ないと理解できない人もいるかもしれません。

見る人の対象は、「awkってなんだろう?」 「awkを1から復習したい」みたいに思っている人だと思います。

【記事紹介2】AWKコマンドの使い方

上で紹介してある記事がawkについての概念をざっと話していたのに対し、 この記事では、「構文」「変数」「関数」「演算子」と項目が分かれており、 実践的なスクリプトを紹介しながらawkについて説明していく、 具体的な内容となっています。

中級者向け(awkについて知っているけど、マスターはしていない人)であり、 awkを復習する人にも大変良い記事だと思いました。

【本紹介1】AWK実践入門 (Software Design plus)

awkは現在でもUnix環境で標準で用意されており、 それを現代の環境に合わせて正規表現や構文、使い方などを説明してくれています。

基本的な構文、awkの肝である正規表現、 1行ずつの典型的なレコード処理、テーブルの結合を含むデータベース操作、 など、たくさんの実践的な要素をたくさん含んでいます。

木構造や有向グラフ、構文解析、行エディタなどを紹介し、 「そんな機能もあるんだ!」 とハッとさせられる内容が盛りだくさんの一冊です。

サンプルコードがたくさんあり、 実際にコマンドを打ち込んで理解しつつ進めていく事ができるので、 awkをバリバリ使いこなしたい!と思っている人にはピッタリの一冊だと思います!

AKW使い方の例一覧

僕もawkについての美しさに感動し、 それからawkについての情報をたくさん調べた時期があります。

awkはとても有用なツールなのですが、 見慣れないスクリプトから難を示す人もいます。 かくいう僕も、その一人でした。

随分昔ですが、awkスクリプトについて見本的なものを探している時に、 「条件行カウント系」だの「条件行表示系」だの、 awkのスクリプトの一例がまとめてあるサイトにに出会いました。

その時はGoogle Codeが全盛の時代だったので、 それからスクリプトを引っ張って使っていたのですが、 Google Codeの閉鎖とともに、いままで使っていたスクリプトの場所がどこに行くのか (もう、なくなったのかもしれない)わからなくなるのが嫌だったので、 ここに転載した次第です。

もう、転載元はリンク切れとなっていますが、 下記「参考サイト」よりこのスクリプト達の存在したページに飛ぶことが出来ます。

このスクリプトの作者様、ありがとう御座います。

なお、元々無分類で管理されており、 使いづらかったので以下複数のカテゴリーに分類しています。 分類の方法は各タイトル名を見ると、だいたい分かるかと思います。 目次にも、一覧としてカテゴリーとスクリプトの機能の簡単な説明が書かれています。

条件行カウント系

  • 各行のフィールド数を表示する。

    $ awk '{print NF ":" $0}' foo.txt
    
  • 最後の行のフィールド数を表示する。

    $ awk '{s = NF} END {print NF}' foo.txt
    
  • ファイルの行数を数える。

    $ awk 'END {print NR}' foo.txt
    
  • ワード数をカウントする。

    $ awk '{n += NF} END {print n}' foo.txt
    
  • 文字数をカウントする。

    $ awk '{n += length($0)} END {print n}' foo.txt
    

条件行表示系

  • 最初の 10 行を表示する。

    $ awk 'NF >= 10' foo.txt
    
  • 奇数行を表示する。

    $ awk 'NR % 2 == 1' foo.txt
    
  • 偶数行を表示する。

    $ awk 'NR % 2 == 0' foo.txt
    
  • 最初の 1 行を表示する。

    $ awk 'NR == 1' foo.txt
    
  • 最初の 1 行を表示する。

    $ awk '{print; exit}' foo.txt
    
  • 最後の 1 行を表示する。

    $ awk 'END {print}' foo.txt
    
  • 最後の 1 行を表示する。

    $ awk '{last = $0} END {print last}' foo.txt
    
  • 80 文字を越える行を表示する。

    $ awk 'length($0) > 80' foo.txt
    
  • フィールドが 5 以上の行を表示する。

    $ awk 'NF >= 5' foo.txt
    
  • 行番号を 4 桁で表示させる。

    $ awk '{printf("%4d : %s\n", NR, $0)}' foo.txt
    
  • 10 行目から 20 行目までを表示する。

    $ awk 'NR == 10, NR == 20 {print $0}' foo.txt
    
  • 最後の行から表示する。(tac)

    $ '{a[i++] = $0} END {for (j = i - 1; j >= 0;) print a[j--]}' foo.txt
    
  • 正規表現 abc の行を表示する。(grep)

    $ awk '/abc/' foo.txt
    
  • 正規表現 abc にマッチしない行を表示する。(grep -v)

    $ awk '! /abc/' foo.txt
    
  • Pattern にマッチした前の行を表示する。

    $ awk '/Pattern/ {print a} {a=$0}' foo.txt
    
  • Pattern にマッチした前の行を表示する。

    $ awk '{D[NR] = $0} /match/ {print D[NR-1]}' foo.txt
    

条件行消去系

  • 空行を削除する。

    $ awk '/./' foo.txt
    
  • 空行を削除する。

    $ awk 'NF' foo.txt
    
  • 同一行の削除を行う。(uniq)

    $ awk 'a !~ $0; {a = $0}' foo.txt
    
  • 同一行の削除を行う。(uniq)

    $ awk '{if ($0 != line || NR == 1) print; line = $0}' foo.txt
    
  • 行頭の空白とタブを削除する。

    $ awk '{sub(/^[ \t]+/, "")}1' foo.txt
    
  • 行末の空白とタブを削除する。

    $ awk '{sub(/[ \t]+$/, "")}1' foo.txt
    
  • 行頭と行末の空白とタブを削除する。

    $ awk '{gsub(/^[ \t]+|[ \t]+$/, "")}1' foo.txt
    
  • 行頭と行末の空白とタブを削除する。(フィールドも再構成される)

    $ awk '$1 = $1' foo.txt
    
  • ’#’ で始まるコメントを削除する。

    $ awk '{sub(/#.*/, "", $0)}1' foo.txt
    

条件行追加系

  • 一行ごとに改行を追加する。

    $ awk '1;{print ""}' foo.txt
    
  • 一行ごとに改行を追加する。

    $ awk 'BEGIN{ORS="\n\n"};1' foo.txt
    

条件行編集系

  • ファイルに行番号を付ける。

    $ awk '$0 = NR OFS $0' foo.txt
    
  • ファイルに行番号を付ける。

    $ awk '{print NR "\t" $0}' foo.txt
    
  • ファイル毎に行番号を付ける。

    $ awk '{prin FNR "\t" $0}' foo*.txt
    

変換系(例: csv->tsv)

  • CSV (カンマ区切り) から TSV (タブ区切り) への変換を行う。

    $ awk -v FS=',' -v OFS='\t' '$1=$1' foo.txt
    
  • TSV (タブ区切り) から CSV (カンマ区切り) への変換を行う。

    $ awk -v OFS=',' -v FS='\t' '$1=$1' foo.txt
    
  • 改行 CR/LF を LF に変換する。

    $ awk 'sub(/\r$/,"")' foo.txt
    
  • 改行 LF を CR/LF に変換する。

    $ awk 'sub(/$/,"\r")' foo.txt
    

特殊系

  • 最も長い行の長さを表示する。

    $ awk '{if (length($0) > max) max = length($0)} END {print max}' foo.txt
    
  • 標準入力をそのまま標準出力に出力する。

    $ cat foo.txt | awk '{print $0}'
    
  • 標準入力をそのまま標準出力に出力する。

    $ cat foo.txt | awk '1'
    
  • 各フィールドの和を求める。

    $ awk '{for (i = 1; i <= NF; i++) s += $i} $0=s' foo.txt
    
  • ファイルサイズが 0 byte のものを表示する。

    $ ls -al | awk '$5==0 {print $8}'
    
  • Subversion の svn status で ‘?’ の付くファイルを全て svn add する。

    $ svn status | gawk '/^?/{print $2}' | xargs svn add
    
  • さいころを作る。

    $ awk 'BEGIN {srand();print int(rand() #### 6 + 1)}'
    
  • Load Average を表示する。(Linux のみ)

    $ awk '{print $1}' /proc/loadavg
    
  • yes コマンドを作る。(延々と ‘y’ を返す)

    $ awk 'BEGIN {for (;;) print "y"}'
    
  • yes コマンドを作る。(延々と ‘y’ を返す)

    $ awk 'BEGIN {while (awk != "Perl") print "y"}'
    
  • 0 から 100 までの間の乱数を 5 つ表示する。

    $ awk 'BEGIN {for (i = 1; i <= 7; i++) print int(101 #### rand())}'
    
  • 行のソートを行う。(gawk 以上)

    $ gawk '{line[NR] = $0} END {asort(line); for (i = 1; i <= length(line); i++) print line[i]}' foo.txt
    
  • 1 から 10 までの数字を生成する。

    $ awk 'BEGIN {for (i == 1; i <= 10; i++) print i}'
    
  • Apache のログにある IP アドレスからホスト名をリアルタイムで引く。(root のみ)

    tail -f /var/log/httpd/access_log | gawk '{system ("dig -x" $1 " +short")}'
    
  • Apache のログからリンク元をリアルタイムで表示する。(root のみ)

    tail -f /var/log/httpd/access_log | gawk -F\" '$4!~/gauc/&&$4!="-"{fflush();print $4}'
    

もっと知りたいなと思ったときは!

その他、この記事でわからないことがあったら、teratialというサービスを利用するといいと思います。 勇者が初歩的な質問からマニアックな質問に幅広く答えてくれますよ! 是非、一度使ってはいかがでしょうか?

その他、たくさんの本も出ているのでどれか手にってみるのもいいと思います!

参考資料

comments powered by Disqus