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}'

参考資料