[Litz' UNION] > [Dal Segno] > [UNIXたん] > [その7] // [その6][その8]

UNIXたん その7

awk

awkは、1行を適当に分割し、その項目毎に処理を行うプログラマブルフィルタです。
perlではより柔軟なプログラムが可能ですが、まずawkを知っておいた方が良いでしょう。

awkの呼び出し方は3通りあります。
(1) awk 'スクリプト'
(2) awk -f スクリプトファイル名
(3) スクリプトファイル名
※(3)については後述「スクリプトファイルのコマンド化」を参照のこと

スクリプトの構造は、基本的にsedと同様で

処理対象となる行の指定{
 コマンド
 コマンド
}

これを書き連ねます(対象行を指定しなければ全ての行が処理対象となる)。

行の指定方法

BEGIN … いっちゃん初め(データを読み込む前)に1度だけ実行する
END … 最後(最終行の処理が終わった後)に1度だけ実行する
/正規表現/ … 正規表現を含む行
論理式 … 論理式が成り立つ行

以上の4通り。
2つの行指定を「,」で繋いで書くと、範囲指定になる。
※「/^1st/,/^2nd/」 … 「1st」で始まる行から「2nd」で始まる行まで

awkはまずデータを1行読み込み、それを複数の項目に分割します。
分割した時のn番目のフィールドを $n で表します。
また、$0 と書くと、全てのフィールドを表します。

ここで、データをフィールドに分割することについて補足。
デフォルトでは空白(連続しても良い)で区切られますが、区切り文字の変更も可能で、
(a) -F#(#は区切り文字) オプションとつけると、起動時に区切りを指定できます。
(b) プログラム中に FS=#(#は区切り文字) とすると、途中で区切りを変更できます。

では、以下にawkの文法を紹介。

[A]特殊な変数
FS … データをフィールドに分割する際の区切り文字
ARGC … awk起動時の引数の個数
ARGV … awk起動時の引数のリスト。n番目はARGV[n-1]
NF … 現在の行のフィールド数
NR … 今まで読み込んだ入力データの行数

[B]文字列操作命令
gsub(r.s) … 正規表現rにマッチした部分を字列sに変換する
index(s,t) … 文字列sに含まれる文字列tの位置を返す
length(s) … 文字列sの長さを返す
match(s,r) … 文字列s中で正規表現rにマッチする部分の位置を返す
split(s,a,r) … 文字列sを正規表現rで分割し配列aに入れる。rを省略するとFSで分割
substr(s,i,n) … 文字列sのi文字目から最大n文字の部分文字列を返す。nは省略可
tolower(s) … 文字列sの大文字を小文字に変換する
toupper(s) … 文字列sの小文字を大文字に変換する

[C]演算
+, -, *, /, ^, % … それぞれ 和, 差, 積, 商, 冪乗, 剰余
==, !=, <, >, <=, >= … それぞれ =, ≠, <, >, ≦, ≧
= … 代入
!, &&, || … それぞれ否定, 論理積, 論理和
~, !~ … それぞれ正規表現にマッチするなら真, しないなら真
in … 配列に属するなら真、そうでなければ偽
atan2(y,x) … y/xのアークタンジェント
exp(x) … e(自然対数の底)のx乗
sin(x), cos(x) … それぞれx(ラジアン)の正弦, 余弦
log(x) … eを底とする対数(自然対数)
sqrt(x) … xの平方根
int(x) … xを超えない最大の整数
rand(x) … 0からx(省略時は1)までの乱数

[D]制御構造
if (条件) 処理 else 処理 … 条件分岐。else以降は省略可
for (初期化 ; 条件 ; 増減式) 処理 … 条件を満たしている間、処理と増減を繰り返す
for (変数 in 配列) 処理 … 配列内のそれぞれの変数について処理

[E]連想配列
連想配列とは、文字列をキー(添字)とする変数の集まり。
配列名[キー] とすることで、値を参照・代入できます。

「1」が含まれる行の2番目のフィールドを表示
> awk '/1/{print $2}' << EOF
1 one
2 two
11 eleven
EOF

one
eleven


ファイルサイズの合計(隠しファイルを除く)
> ls -al | awk '{if($9 !~ /^\./) s = s + $5}END{print s}'
4099

スクリプトファイルのコマンド化

UNIXでコマンドを自作する方法として、aliasを以前に紹介しました。
その他に、プログラムに対するスクリプト自体を1つのコマンドのようにすることができます。

具体的には、ファイルに

#!プログラム名(絶対パス)
スクリプト(複数行にわたっても良い)


と書きます。すると、

プログラム スクリプト

と入力したのと同等になります。以下に具体例

先程の「ファイルサイズの合計(隠しファイルを除く)」を書き換えてみよう。

#!/bin/awk -f
{if($9 !~ /^\./) s = s + $5}
END{print s}

これを「f-size」という名前で保存し、実行許可を与える(chmod)。
すると、このf-sizeは、コマンドとして扱われる( ls -al | f-size として確認)。

[Litz' UNION] > [Dal Segno] > [UNIXたん] > [その7] // [その6][その8]