awk

機能 概要 正規表現
ユーザ定義関数 パターン
演算子 算術演算子 比較演算子 論理演算子
変数 一般変数 配列 組込み変数
組込み関数 算術関数 文字列関数 入出力関数 その他関数
入出力 出力 入力 パイプへの入出力
文字 メタ文字 エスケープ文字列 特殊文字
実行 オプション コマンド行引数 エラー対処法
その他 FAQ 練習問題 参考書 練習問題の解


機能

概要

awk は、すべての入力行に対して指定したパターンに適合しているかを検査し、 適合した場合は対応するアクションを実行するインタープリタです。

言語の名前の由来は、これを作った人々の名前からきています。
すなわち a(Aho) w(Weinberger) k(Kernighan) でオークと読みます。
オープンソースの gawk(gnu awk) は、ここからダウンロードして自由につかえます。

パターンは、アクションの実行を制御します。 すなわち、パターンに適合した場合は、対応するアクションが実行されます。

awk のプログラムは、1つまたはそれ以上のパターンアクション文の列です。

パターン  { アクション }
パターン  { アクション }

[ 例1 ] $3 == 0 { print $1 } 3 番目の欄が文字0である全行を印字する
[ 例2 ] samp2.data USSR 8649 275 Asia Canada 3852 25 North America China 3705 1032 Asia USA 3615 237 North America Brazil 3286 134 South America India 1267 746 Asia Mexico 762 78 North America France 211 55 Europe Japan 144 120 Asia Germany 96 61 Europe England 94 56 Europe samp2.awk /Asia/ { count["Asia"] ++ } /America/ { count["America"] ++ } /Africa/ { count["Africa"] ++ } /Australia/ { count["Australia"] ++ } /Europe/ { count["Europe"] ++ } END { for (name in count) printf("%-10s : %4d\n",name,count[name]) } ozzy-10 08/23 1:34pm] nawk -f samp2.awk samp2.data Asia : 4 Europe : 3 America : 4
samp21.awk BEGIN { fmt = "%10s %6s %10s %s\n" printf("\n") printf(fmt,"COUNTRY","AREA","POPULATION","CONTINENT") } { printf(fmt,$1,$2,$3,$4) ttl_area += $2 ttl_pop += $3 } END { printf(fmt,"TOTAL",ttl_area,ttl_pop,"") } ozzy-14 08/23 2:05pm] nawk -f samp21.awk samp2.data COUNTRY AREA POPULATION CONTINENT USSR 8649 275 Asia Canada 3852 25 North China 3705 1032 Asia USA 3615 237 North Brazil 3286 134 South India 1267 746 Asia Mexico 762 78 North France 211 55 Europe Japan 144 120 Asia Germany 96 61 Europe England 94 56 Europe TOTAL 25681 2819

awk のプログラムをファイルに格納する場合は、拡張子として .awk を使います。
パターンには、以下のものがあります。

パターン 書   法 意      味
BEGIN BEGIN { 文 } 入力行が読まれる前に、一度だけ文を実行する
END END { 文 } 入力行が終了後に、一度だけ文を実行する
式 { 文 } 式が真である入力行の場合、文を実行する
正規表現 /正規表現/ { 文 } 正規表現に適合する入力行の場合、文を実行する
複合パターン 複合パターン { 文 } 複合パターンが真である入力行の場合、文を実行する
範囲指定のパターン パターン1,パターン2 { 文 } パターン1 に適合する入力行からパターン2
に適合する入力行の次までの文を実行する

Solaris では awk の最新版である nawk(new awk) を使ってください。




正規表現

正規表現は、文字列を指定したり照合するのに使う記法です。 ここでは概要のみ記述します。
詳細は正規表現を参照してください。

意      味
c 非メタ文字 c AA
\c 文字 c \* *
^ 文字列のはじめ ^[ABC] A,B,C
$ 文字列のおわり ^$ 空行
. 任意の文字 . 任意1文字
[c1c2...] c1c2...の中の任意の文字 [ABC] A,B,C
[^c1c2...] c1c2...の中にない任意の文字 [^ABC] D,E,F....
[c1-c2] c1 から c2 までの範囲の任意の文字 [0-9]* 10進数
[^c1-c2] c1 から c2 までの範囲にない任意の文字 [^A-Z]+ 大文字を含まない単語
r1|r2 r1 か r2 に適合する任意の文字列 (black|blue) black,blue
(r1)(r2) r1 が x に、 r2 が y に適合するような xy (black)(blue) blackblue
(r)* r に適合する文字列の 0 個以上の連結 (AB)*C C,ABC,ABABC,..
(r)+ r に適合する文字列の 1 個以上の連結 (AB)+C ABC,ABABC,..
(r)? r に適合する 0 または 1個の文字列 (AB)?C C,ABC
(r) r に適合する任意の文字列 (AB) AB

c = 文字
r = 正規表現文字列




awk の文は c 言語をモデルにしていますので、類似しています。 文は、アクション部でのみ利用できます。

文種類 書式
コメント # コメント # this is a comment
選択文 if (式) 文 if (NR>2) print $0
if (式)
 文
else
 文
if (NF) print $0 
else printf("\n")
繰り返し文 for (式;式;式)文群 for (i=1; i<=;NF; i++) print $i
for ( 変数 in 配列)文 for ( i in pop ) delete pop[i]

pop にある全ての要素を消去する

while (式) {
 文
}
i=1
while ( i<= NF ) { 
   print $i 
   i++ 
} 
do {

} while (式)
i=1
do  {
   print $i 
   i++ 
} while ( i<= NF )  
制御移行文 next 最も内側のループを繰り返す
break 最も内側のループから抜ける
continue 最も内側のループの次の繰り返しへ実行を移す
exit(式) 式の値はシェルに返される
return(式) 式の値が返される




ユーザ定義関数

awk に組み込まれた関数の他に、ユーザが定義した関数も利用できます。
ユーザ関数の定義は、パターンアクションを書けるところであればどこでも書けます。

項目 書        式
定義 
function  名前(引数並び) { 
文の並び 
return 式 } 引数は局所的ですが、それ以外の変数は大域的です。 引数以外に局所変数を使いたい場合は、実引数の後ろに書きます。 それらは初期値空の局所変数となります。 従って、関数から関数を呼ぶ場合、i,j,k 等が 重複しないようにしなければなりません。
function max(m,n) {
   return m > n ? m: n
}
参照 
関数名(引数列)
引数は局所的ですが、それ以外は大域的です。 
ind = max(m,n)

ユーザ定義関数の例を示します。
年月日が書かれたファイルを読んで、その日が何曜日かを返すプログラムです。 曜日は 0 からはじまる数値で、0 は日曜日を表します。

[ getweek.awk ]
BEGIN  {
   WRK_FILE = "/tmp/cal.tmp"
   WEEK     = 7
}

{
   ret = split($1,ary,"/")                        # yyyy/mm/dd が $1 に入る
   yyyy= ary[1]
   mm  = ary[2]
   dd  = ary[3]

   ret = get_week(yyyy,mm,dd)
   printf("%d/%02d/%02d is %d\n",yyyy,mm,dd,ret)
}

#------------------------------------------------------------------------
#  Function : get day's of week of specified date
#  Param    : yy  -- year
#             mm  -- month
#             dd  -- day
#  LocalVar : ret,i
#------------------------------------------------------------------------
function get_week(yy,mm,dd,ret,i)  {         # 局所変数の宣言
   system("cal " mm " " yy " > " WRK_FILE)   # コマンド cal を呼び結果を WRK_FILE に書く
   for (i=0; i<3; i++)  {
      getline line < WRK_FILE
   }
   ret = split(line,ary2," ")          # line にはじめの週のデータを入れる
   first = (WEEK - ret)
   mod   = (dd + first -1) % WEEK
#printf("ret=%d  line=%s  first=%d  mod=%d\n",ret,line,first,mod)
   close WRK_FILE
   system("rm " WRK_FILE)
   return (mod)
}

[ 実行結果  ]  date=2004/12/01
> nawk -f getweek.awk date
2004/12/01 is 3




パターン

パターンは、アクションの実行を制御します。 すなわち、パターンに適合した場合、対応するアクションを実行します。

パターン適合するもの
BEGIN BEGIN レコード入力前の処理
END END レコード入力終了後の後処理
/正規表現/ /Asia/ 正規表現を含む文字列に適合:Asia を含む行
式 ~ /正規表現/ $4 ~/Asia/ 式が正規表現を含む時適合:$4 が Asia を含む行
式 !~ /正規表現/ $4 !~/Asia/ 式が正規表現を含まない時適合:$4 が Asia を含まない行
パターン && パターン /Asia/ && $3 >500 Asia を含みかつ3欄の値が 500 より大きい行
パターン || パターン /Asia/ || /Europe/ Asia か Europe を含む行
! パターン ! /Asia/ Asia を含まない行
(パターン) (Asia|Europe) Asia か Europe を含む行
パターン , パターン NR==10,NR==20 10 行目から 20 行目までの行(20 行目も含む)

複数の SQL 文のスプール結果をそれぞれに分離するプログラムです。 それぞれ sql.N の名前のファイルを出力します。

[ sql_pick.awk ]
BEGIN  {
   file_no = 0
   FILE    = "sql."
   OUT     = ""
}

/^SQL> spool off/  {
   next
}

/^(SQL> )+/ {
   if (OUT != "")    close(OUT)
   OUT = FILE  file_no
   file_no ++
   next
}

/選択されました。/  {
   next
}

/~$/   {
   next
}

{
   printf("%s\n",$0)  >> OUT
}

[ 実行結果 ]
> nawk -f sql_pick.awk 040927.log
> ls -l sql.*
-rw-r--r--   1 taka     dba        76758 10月  6日  13:38 sql.0
-rw-r--r--   1 taka     dba          925 10月  6日  13:38 sql.1
-rw-r--r--   1 taka     dba          245 10月  6日  13:38 sql.2
-rw-r--r--   1 taka     dba         1868 10月  6日  13:38 sql.3




演算子

演算子は、算術演算子、比較演算子、論理演算子、文字列演算子があります。

文字列演算子は連結のみで、明示的な演算子は必要ありません。 ただ並列に1つずつならべることで実現できます。 従って、これについては書きませんが、例題を以下に示します。

[ concat.awk ]
BEGIN   {
   con  = "."
   str0 = "Japan"
   str1 = "kanagawa"
   str2 = "yokohama"

   loc = str0 con str1 con str2        # 連結
   printf("%s\n",loc)
}

[ 実行結果 ]
> nawk -f concat.awk aaa
Japan.kanagawa.yokohama

算術演算子

演算子の優先順位は、下にいくほど高いです。

演算子意味 a の値
= 代入 a = 1 1
+= 代入 a += 1 2
-= 代入 a -= 1 1
*= 代入 a *= 12 12
/= 代入 a /= 2 6
%= 代入 a %= 7 6
^= 代入 a ^= 3 216=6*6*6
?: 条件式 a = (a>10)?1:0 1
|| 論理和 a = (a>0) || (a<100) 1
&& 論理積 a = (a>0) && (a<100) 1
in 配列要素 a = (a in b) 0
+ a = (a + 10) 10
- = (a - 5) 5
* a = (a * 5) 25
/ a = (a / 5) 5
% 剰余 a = (a % 7) 5
- 符合反転 a = -a -5
! 論理否定 a = (!a) 0
^ 累乗 a = (a ^ 5) 0
++ インクリメント a ++ 1
-- デクリメント a-- 0
$ $i+1 -




比較演算子

< より小さい if (no < 0) print $0
<= 以下 if (no <= 0) exit(1)
== 等しい   if (no == "AAA") exit(1)
!= 等しくない if (no != 0) exit(1)
>= 以上    if (no >= 0) exit(1)
> より大きい if (no > 0) exit(1)
~ 適合する  if (no ~ /[a-zA-Z0-9]+/ ) exit(1)
!~ 適合しない if (no !~ /[a-zA-Z0-9]+/ ) exit(1)

論理演算子

?: 条件式 (a>10)?1:0
|| 論理和 (a>10) || (a<100)
&& 論理積 (a>10) && (a<100)




変数

式は、ユーザが定義した変数や組み込み変数などを含みます。 また awk の変数は、値として文字列あるいは数値の両方を持っています。 awk は変数の値を文脈から判断して自動的に変換します。 すなわち、掛け算の中で使う変数の値は数値に自動変換されます。

一般変数

変数は宣言する必要はありません。 関数の引数並びの変数以外のすべての変数は大域的です。

初期化されていない変数は、 数値0と文字列値 "" を持つものとして生成されます。 値は、数値、文字列値を自由に変換できます。 明示的に変換するには、以下のようにします。

string = 数値 ""              数値に空の文字列を連結して、文字列値に変換します
number = 文字列値 + 0         文字列値にゼロを加算して、数値に変換します




配列

文字列や数を格納するために1次元の配列が用意されています。 これらは宣言する必要がないばかりか、要素数も指定する必要がありません。

配列は使われると同時に存在し、 その初期値は変数と同様に数値0と文字列値 "" を持ちます。

awk の配列の添え字は文字列で、 このような配列を連想配列 (associative array) といいます。

pop["Asia"] = "Japan"
pop[Asia]   = "Japan"

以下の構文は、 配列の異なる添え字1つ1つを順番に変数に設定しながら文を実行します。

for ( 変数 in 配列)
  文

多次元配列は直接はサポートしていませんが、 1次元配列を使って模倣できます。

awk は i,j のような多次元配列の添え字を使ってそれらを連結し、 1次元配列の添え字を生成します。

for (i=1; i<=10; i++)
  for (j=1; j<=10; j++)
    arr[i,j] = 0




組込み変数

awk には、以下の組み込み変数があります。 これらの変数は、すべての文で利用でき、ユーザが値をかえることもできます。

名前 意      味 既定値
ARGC コマンド行にある引数の数 -
ARGV コマンド行引数の配列 ARGV[0 .. ARGC-1] ARGV[0] は awk プログラム名
FILENAME 現在の入力ファイル名 -
FNR 現在のファイルの入力レコード数 -
FS 入力欄区切子 空白
$0 現在の入力レコード -
$1 ..$n 現在の入力レコードの n 欄目のもの -
NF 現在の入力レコードの欄数 -
NR 起動後のすべての入力レコード数 -
OFMT 数の出力書式 %.6g
OFS 出力欄区切子 空白
ORS 出力レコード区切子 改行(\n)
RLENGTH match のなかで正規表現と適合した文字列の長さ -
RS 入力レコード区切子 改行(\n) その他(\r,\f,\r\f)
RSTART match で適合した文字列の開始位置 (1 origin) -
SUBSEP [i,j...] の形の配列の添字に使う区切子 \034




組込み関数

算術関数

関数名意      味
atan2(y,x) -πからπの間のラジアンで表した y/x の逆正接
cos(x) 余弦(角度の単位はラジアン)
exp(x) 指数関数 ex
int(x) 小数点以下を切り捨てた整数値
log(x) 自然対数
rand() 擬似乱数値 0
sin(x) 正弦(角度の単位はラジアン)
sqrt(x) 平方根
srand(x) 乱数生成のための新しい種を設定




文字列関数

文字列を加工するための関数があります。 それぞれの記号には次の意味があります。

t = 入力文字列
s = 置換文字列
r = 正規表現文字列
a = 文字列配列
fs = 入力欄区切子

関数名意      味
gsub(r,s,t) t の部分文字列で r に適合するものを全て s で置換し、置換数を返す。
t を省略すると $0 を使う
ret = gsub(/JP/,"JAPAN",$0)
index(s,t) s の中の t の位置を、 t がないときは 0 を返す ret = index($0,"JAPAN")
length(s) s の長さを返す ret = length($0)
match(s,r) s が r に適合する位置を、非適合の場合は 0 を返す
RSTART,RLENGTH を設定
ret = match($0,/JAPAN/)
split(s,a,fs) fs を区切子として s を配列 a に分解し、欄数を返す
a には1オリジンで格納されます。 fs を省略すると FS を使う
ret = split($0,ary,":")
sprintf(書式、式の並び) 書式で整えた式の並びを返す ret = sprintf("%s %s %s",cmd1,cmd2,cmd3)
sub(r,s,t) 最初に適合した部分文字列を置換し、置換数を返す ret = sub(/[a-zA-Z]*/,"",$0)
substr(s,i,n) s の i 番目から始まる n 文字の部分文字列を返す(i は1オリジン)
n を省略すると s の i 番目から始まる接尾語を返す
ret = substr($1,1,10)




入出力関数

関数名意      味
close(式)式のファイルまたはパイプを閉じる close($3)
getline
次の入力レコードが $0 に入る
NF,NR,FNR もセットする

[ 戻り値 ]
レコードあり  :1
EOF           :0
オープンエラー:-1
DATE_FILE = "date.today"
system("date +'%y/%m/%d %H:%M:%S'> "
        DATE_FILE)
ret = getline today < DATE_FILE 
getline < ファイル ファイルの次レコードが $0 に入る
NF もセットする
getline < .cshrc
getline 変数 次の入力レコードが変数に入る
NR,FNR もセットする
getline lbuf
getline 変数 < ファイル
ファイルの次レコードが変数に入る

[ 戻り値 ]
レコードあり  :1
EOF           :0
オープンエラー:-1
while(getline lbuf < .cshrc > 0)
print指定レコードを出力する print $0
print 式の並び式の並びの中の式を出力する print $1,$2
print 式の並び > ファイルファイルに式を出力する print $1 $2 > "out"
printf (書式、式の並び)書式を整えて出力する printf("str=%s num=%d\n",str,num)
printf (書式、式の並び)
> ファイル
ファイルに書式を整えて出力する printf ("str=%s num=%d\n",str,num) > "out"
printf (書式、式の並び)
>> ファイル
ファイルに書式を整えて追加出力する printf("str=%s num=%d\n",str,num) > "out"
printf (書式、式の並び)
| コマンド
書式を整えて出力した文字列を
コマンドの入力とする
printf("str=%s num=%d\n",str,num) | "sort"




その他関数

関数名意      味
system (コマンド) コマンドを実行して
終了コードを返す
system("ls")
system("sort +3 -r " filenm " >> " filenm1) 
system("sort -un "  WORK_PORT " > " SORT_PORT) : 数値の場合
system("cal " mm " " yy)   :変数を続けるときは空白で区切る




入出力

入出力は通常上記の入出力関数を使って行います。 ファイルへの入出力などは UNIX コマンドで使うものと同じ演算子 (>,>>,<) を利用できます。
また標準入力、標準出力、標準エラーのファイル名は "/dev/stdin","/dev/stdout","/dev/stderr" です。

出力

書式つきの出力は、printf 文を使います。書式は c 言語のものと同じです。

意味
print stdout に $0 を出力する
print 式,式,... stdout に式を OPS で区切りながら出力し ORS で終了する
print 式,式,... > ファイル名 ファイル名に式を OPS で区切りながら出力し ORS で終了する
print 式,式,... >> ファイル名 ファイル名に追加する
print 式,式,... | コマンド 式を出力した内容をコマンドの入力とする
printf(書式,式,...,式) stdout に式を書式に従って出力する
printf(書式,式,...,式) > ファイル名 式を書式に従ってファイルに出力する
printf(書式,式,...,式) >> ファイル名 式を書式に従ってファイルに追加して出力する
printf(書式,式,...,式) | コマンド 式を書式に従って出力した内容をコマンドの入力とする

入力

awk の入力では、いくつかの手法が用意されています。
  1. 最も普通の方法は、コマンド列でファイル名を指定します。
    組み込み変数 FS は入力欄区切子なので、これにより欄区切子を変更できます。
  2. getline 関数を利用する。
    現在の入力の他にファイルやパイプからの入力が可能です。

被設定変数
getline $0,NF,NR,FNR
getline 変数名 変数,NR,FNR
getline < ファイル $0,NF
getline 変数名 < ファイル 変数
コマンド | getline $0,NF
コマンド | getline 変数名 変数

パイプへの入出力

書式意      味
コマンド | getline コマンドの出力を $0,$1,..$N に行情報として設定する
コマンド | getline 変数名 コマンドの出力を変数に設定する
print | コマンド コマンドへの入力とする
print メッセージ | "cat 1>&2" stderr へ出力する




文字

メタ文字

メタ文字は、正規表現を表すために使う文字のことです。

メタ文字意      味 適合文字列
\ エスケープ・シーケンスをあらわす \nnewline
^ 文字列のはじめをあらわす    [^a-z]bab,zb
$ 文字列のおわりをあらわす    AA[a-z]$AAb,AAa
. 任意の1文字をあらわす    [a-z].a1,e4
[ ] 文字クラス内の任意の1文字に適合する [a-z]a,b,c
| 選択をあらわす    (A|B)$A,B
( ) グループ化をあらわす    (AB)+CABC,ABABC,ABABABC,...
* ゼロ個以上の並びからなる任意の文字列をあらわす [a-z]*asas etc
+ 1 個以上の並びからなる任意の文字列をあらわす [a-z]+asas etc
- 文字の範囲をあらわす    [a-z]a,b,c
? 空か適合する任意の文字をあらわす  A?CC,AC




エスケープ文字列

メタ文字列は、文字列および正規表現の中で特別な意味をもちます。

エスケープ文字列意      味
\b バックスペース \b
\f フォームフィード \f
\n 改行 \n
\r 復帰 \r
\t タブ \t
\ddd 8進数 ddd(ただし ddd は 0 から 7 までの3桁の数字) \127
\c 任意の文字 c そのもの。\\ は \ を表す \\




特殊文字

sub(r,s,t) や gsub(r,s,t) によって行われる置換においては、 s の中の任意の文字 & は r に適合した部分文字列に置き換えられます。
従って下の2つは同じで、"babanabanaba" になります。

gsub(/a/,"aba","banana")
gsub(/a/,"&b&","banana")

置換文字列の中の & の特殊な意味をなくしたい場合は、 \& とします。例えば "<" を "&lt;" に変換するには、以下のようにします。

gsub(/</,"\\&lt;",$0)




実行

awk プログラムの実行には、いろいろな方法があります。

awk 'プログラム' 入力ファイル群
awk -f awk プログラムファイル 入力ファイル群

[ 例 ] awk '$3==0 { print $1 }' file1 file2 awk -f pick.awk file1 file2

オプション

オプション意      味
-f awk のプログラムを指定 awk -f arg.awk aaa bbb
-F FS を指定 awk -F' ' -f arg.awk aaa bbb




コマンド行引数

f1,f2 のファイルの各行をプログラムで処理する。ただし f1,f2 は通常ファイルです。

コマンド行 説明
awk 'プログラム' f1 f2 ... f1,f2 はプログラムの入力ファイルとして扱われる
awk -f プログラム f1 f2 ... f1,f2 はプログラムの入力ファイルとして扱われる
awk -F 区切子 'プログラム' f1 f2 ... f1,f2 はプログラムの入力ファイルとして扱われる
awk -F 区切子 -f プログラム f1 f2 ... f1,f2 はプログラムの入力ファイルとして扱われる
awk -f プログラム f1 f2 var=text f1,f2 はファイルとして扱われるが、var=text は var への text の代入です

最後の var=text の使い方の例を示します。
var をプログラム内で使用したいときなど便利です。

 例 : arg.awk 
#--------------------------------------------------------------------------
# Function : print argument lists
# Usage    : nawk -f arg.awk 111 DATA_CNTL=aaa DATA_RSLT=bbb
# Result   : arg0=nawk  arg1=111  arg2=DATA_CNTL=aaa  arg3=DATA_RSLT=bbb  argc=4
#            arg2 = aaa
#            arg3 = bbb
#---------------------------------------------------------------------------
BEGIN {
  for (i=0; i<ARGC; i++) {
     printf("arg%d=%s  ",i,ARGV[i]);
  }
  printf("argc=%d\n",ARGC);
  arg2 = ARGV[2]
  arg3 = ARGV[3]
  ret = match(arg2,/DATA_CNTL[ ]*=/)
  if (ret)   printf("arg2 = %s\n",substr(arg2,RSTART+RLENGTH))
  ret = match(arg3,/DATA_RSLT[ ]*=/)
  if (ret)   printf("arg3 = %s\n",substr(arg3,RSTART+RLENGTH))
}

> nawk -f arg.awk 111 DATA_CNTL=aaa DATA_RSLT=bbb arg0=nawk arg1=111 arg2=DATA_CNTL=aaa arg3=DATA_RSLT=bbb argc=4 arg2 = aaa arg3 = bbb




エラー対処法

現象 理由 対処
id = $1/1000 では id が整数でないため添え字として配列を参照できない 値が整数値でないため id = int($1/1000)




その他

  1. 引数配列
  2. 先頭フィールドを合計し合計値と平均値を出力
  3. 全行から CR を削除
  4. c ソースを html 形式に変換
  5. ls -l の9カラム目をとりだし ' で囲む

項目コード
引数配列

ARGV[0]:awk program
ARGV[1]:1st arg
ARGV[2]:2nd arg
BEGIN {
   for (i=0; i<ARGC; i++)  print ARGV[i]
}

> nawk -f echo.awk aaa bbb nawk aaa bbb
先頭フィールドを合計し
合計値と平均値を出力
{     s += $1 }
END {
   print "sum is ", s, " average is", s/NR
}
CR を削除

rmCR
{
   gsub(/^M/,"")
   print $0
}
c ソースを html 形式に変換
BEGIN  {
   gt = "&" "gt;"
   lt = "&" "lt;"
   printf("<HTML><BODY>\n")   }
{
   gsub(/</,lt)
   gsub(/>/,gt)
   printf("%s\n",$0)
}
END    {  printf("</BODY></HTML>\n")   }
ls -l の9カラム目をとりだし ' で囲む
BEGIN {
   str = "\'"
}

{
   printf("%s%s%s\n",str,$9,str)
}

ls -l | nawk 'BEGIN {ch=39+0}{printf("%c%s%c\n",ch,$9,ch)}'

FAQ

No 質問 対処法
1 solaris で awk を使うとプログラムは正しいのにエラーになる nawk を使うこと。
awk はすでにサポートしていない
2 awk に変数値を引き渡す方法は? who | awk '$1 == user { print $2 }' user="$USER"




練習問題

  1. 指定のファイルを行番号付で出力しなさい。
    データ:proc1.pc プログラム名:no.awk

    BEGIN {
       fmt  = sprintf("%%%dd ",5)
       printf("%s]\n",fmt)
    }
     ===> 
       1  BEGIN {
       2     fmt  = sprintf("%%%dd ",5)
       3     printf("%s]\n",fmt)
       4  }
    

  2. 行番号付のレコードの行番号をはずしなさい。上記の逆です。
    プログラム名:nonno.awk

  3. oracle の alert ファイルは以下のように日付が途中にあってわかりずらいので、 次にように先頭につけて remake しましょう。
    プログラム名:alert.awk

    alter database open
    Sun Feb 27 04:00:53 2005
    Thread 1 opened at log sequence 1437
      Current log# 3 seq# 1437 mem# 0: /oracle/oradata/SA04/dbs/log3SA04.dbf
    Successful open of redo thread 1.
    Sun Feb 27 04:00:53 2005
    SMON: enabling cache recovery
    SMON: enabling tx recovery
    Sun Feb 27 04:00:54 2005
    Completed: alter database open
    Shutting down instance (normal)
    License high water mark = 1
    Sun Feb 27 04:01:14 2005
    ALTER DATABASE CLOSE NORMAL
    Sun Feb 27 04:01:14 2005
    SMON: disabling tx recovery
    SMON: disabling cache recovery
     ===> 
    alter database open
    02/27 04:00:53] Sun Feb 27 04:00:53 2005
    02/27 04:00:53] Thread 1 opened at log sequence 1437
    02/27 04:00:53]  Current log# 3 seq# 1437 mem# 0: /oracle/oradata/SA04/dbs/log3SA04.dbf
    02/27 04:00:53] Successful open of redo thread 1.
    02/27 04:00:53] Sun Feb 27 04:00:53 2005
    02/27 04:00:53] SMON: enabling cache recovery
    02/27 04:00:53] SMON: enabling tx recovery
    02/27 04:00:54] Sun Feb 27 04:00:54 2005
    02/27 04:00:54] Completed: alter database open
    02/27 04:00:54] Shutting down instance (normal)
    02/27 04:00:54] License high water mark = 1
    02/27 04:01:14] Sun Feb 27 04:01:14 2005
    02/27 04:01:14] ALTER DATABASE CLOSE NORMAL
    02/27 04:01:14] Sun Feb 27 04:01:14 2005
    02/27 04:01:14] SMON: disabling tx recovery
    02/27 04:01:14] SMON: disabling cache recovery
    

  4. ps -efl の結果から oracle プロセスを取り出して、 SZ の大きい順に並べましょう。
    表示する項目は PID/PPID/SZ/TIME/CMD です。
    プログラム名:get_ora.awk

  5. 英語の文章があります。各単語が何回出てくるか印刷しましょう。
    - , . () " などで囲まれた単語のそれらを無視します。
    データ:crossref.data プログラム名:crossref.awk

    Text editors are applications which are used strictly for editing and
    transforming text. In this context, "text" means a document which
    contains any arbitrary combination of characters, including letters,
    numbers, punctuation marks, and other symbols. Some examples include
    PostScript text files, BinHex or uuencoded data files, program source
    code files, or documents such as this one. The functional emphasis for
    a text editor is on manipulation of characters and lines (often within
    very large files), rather than words or other units of written
    language. This of course does not imply that text editors cannot or
    should not have word-oriented functions as well, but rather that they
    must handle a variety of arbitrary types of file content which word
    processors are not optimized for.
     ===> 
         BinHex               :  1
         In                   :  1
         PostScript           :  1
         Some                 :  1
         Text                 :  1
         The                  :  1
         This                 :  1
         a                    :  3
         and                  :  2
         any                  :  1
         applications         :  1
         arbitrary            :  2
         are                  :  3
         as                   :  2
         but                  :  1
         cannot               :  1
         characters           :  2
         code                 :  1
         combination          :  1
         contains             :  1
         content              :  1
         context              :  1
         course               :  1
         data                 :  1
         document             :  1
         documents            :  1
         does                 :  1
         editing              :  1
         editor               :  1
         editors              :  2
         emphasis             :  1
         examples             :  1
         file                 :  1
         files                :  4
         for                  :  1
         functional           :  1
         functions            :  1
         handle               :  1
         have                 :  1
         imply                :  1
         including            :  1
         is                   :  1
         language             :  1
         large                :  1
         lines                :  1
         manipulation         :  1
         marks                :  1
         means                :  1
         must                 :  1
         not                  :  3
         numbers              :  1
         of                   :  6
         often                :  1
         on                   :  1
         one                  :  1
         optimized            :  1
         or                   :  3
         oriented             :  1
         other                :  2
         processors           :  1
         program              :  1
         punctuation          :  1
         rather               :  2
         should               :  1
         strictly             :  1
         such                 :  1
         symbols              :  1
         text                 :  5
         than                 :  1
         that                 :  2
         this                 :  2
         transforming         :  1
         types                :  1
         units                :  1
         used                 :  1
         uuencoded            :  1
         variety              :  1
         very                 :  1
         well                 :  1
         which                :  2
         word                 :  1
         words                :  1
    

  6. 次の表の縦横の総和と平均を求めましょう。
    データ:matrix.data プログラム名:matrix.awk

       28670   22483  1253978     623   1  18002  433526
       27610   22144  1156768     502   2  17559  312027
       26121   21032  1097266     448   3  16683  335951
       27495   21827  1175768     524   4  17365  332899
       28233   22446  1221040     533   5  17924  420386
       31811   25543  1439033     574   6  20241  382184
       31642   25059  1313149     583   7  20013  409582
       34176   26893  1484714     686   8  21490  456873
       33977   26792  1451724     677   9  21372  424977
       34191   26876  1504664     721  10  21461  457493
       35542   28111  1581898     719  11  22510  568686
       32122   25527  1416194     619  12  20317  438023
       32092   25512  1399793     578  13  20334  456054
       32752   25536  1493162     737  14  20484  489811
       32910   25937  1429445     651  15  20765  468834
       33871   27323  1447990     575  16  21658  380243
       36582   28973  1623478     737  17  23100  450918
       39572   30910  1732042     856  18  24861  598125
       36296   28674  1654706     742  19  22893  499566
       37426   29112  1655542     854  20  23465  559575
     ===> 
         28670      28670      22483    1253978        623          1      18002      1352427
         27610      27610      22144    1156768        502          2      17559      1252195
         26121      26121      21032    1097266        448          3      16683      1187674
         27495      27495      21827    1175768        524          4      17365      1270478
         28233      28233      22446    1221040        533          5      17924      1318414
         31811      31811      25543    1439033        574          6      20241      1549019
         31642      31642      25059    1313149        583          7      20013      1422095
         34176      34176      26893    1484714        686          8      21490      1602143
         33977      33977      26792    1451724        677          9      21372      1568528
         34191      34191      26876    1504664        721         10      21461      1622114
         35542      35542      28111    1581898        719         11      22510      1704333
         32122      32122      25527    1416194        619         12      20317      1526913
         32092      32092      25512    1399793        578         13      20334      1510414
         32752      32752      25536    1493162        737         14      20484      1605437
         32910      32910      25937    1429445        651         15      20765      1542633
         33871      33871      27323    1447990        575         16      21658      1565304
         36582      36582      28973    1623478        737         17      23100      1749469
         39572      39572      30910    1732042        856         18      24861      1867831
         36296      36296      28674    1654706        742         19      22893      1779626
         37426      37426      29112    1655542        854         20      23465      1783845
     ---------  ---------  ---------  ---------  ---------  ---------  ---------  ===========
        653091     653091     516710   28532354      12939        210     412497     30780892
         32654      32654      25835    1426617        646         10      20624      1539044
    




参考書

【 関連項目 】

nawk(1),awk(1)

練習問題の解

  1. 指定のファイルを行番号付で出力しなさい。

    {
       printf("%5d %s\n",++lno,$0)
    }
    

  2. 行番号付のレコードの行番号をはずしなさい。上記の逆です。

    {
       gsub(/^[ ]*[0-9]+ /,"",$0)
       printf("%s\n", $0)
    }
    

  3. oracle の alert ファイルは以下のように日付が途中にあってわかりずらいので、次にように先頭につけて remake しましょう。

    {
       if ($0 ~ /(Sun|Mon|Tue|Wed|Thu|Fri|Sat) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-9]+) ([0-9:]+) ([0-9]+)/) {
    #       printf("2=%s 3=%s 4=%s 5=%s %s",$2,$3,$4 ,$5,line)
           mon = change_mon($2)
           day  = $3
           time = $4
           year = $5
           cur_time = sprintf("%02d/%02d %s] ",mon,day,time)
       }
       printf("%s%s\n",cur_time, $0)
    }
    
    function change_mon(mon_str)  {
          SZ_MON = 12
          mon_ary[ 0] = "Jan"
          mon_ary[ 1] = "Feb"
          mon_ary[ 2] = "Mar"
          mon_ary[ 3] = "Apr"
          mon_ary[ 4] = "May"
          mon_ary[ 5] = "Jun"
          mon_ary[ 6] = "Jul"
          mon_ary[ 7] = "Aug"
          mon_ary[ 8] = "Sep"
          mon_ary[ 9] = "Oct"
          mon_ary[10] = "Nov"
          mon_ary[11] = "Dec"
          for (i=0; i<SZ_MON; i++)  {
             if (mon_str == mon_ary[i])  
                return i+1
          }
    }
    

  4. 英語の文章があります。各単語が何回出てくるか印刷しましょう。

    {
    # 連想配列の作成
       gsub(/[ \[\]\.\(\)\t,"\/\n\r\-]/," ",$0)
       ret = split($0,ary," ")
       for (i=0; i<ret; i++)  {
          word = ary[i]
          if (word == "")  continue
          if (word in word_ary)   word_ary[word] ++
          else {
             word_ary[word] = 1
          }
       }
    }
    
    END  {
    # 連想配列の印刷
       FOUT = "crs"
       i = 0
       for (word in word_ary)  {
          printf("%-20s : %2d\n",word,word_ary[word]) >> FOUT
          i++
       }
       system("sort crs")
    }
    

  5. 次の表の縦横の総和と平均を求めましょう。

    BEGIN  {
       lno = 0
       COL = 7
    }
    {
       lno += 1
       yoko = 0
       for (i=0; i<NF; i++)  {
          yoko        += $i
          ttl_tate[i] += $i
          printf("%10d ",$i)
       }
       ttl_tate[NF]  += yoko
       printf("%12d\n",yoko)
    }
    
    END   {
    # 総計を出力
       for (i=0; i<COL; i++) {
          printf(" %9s ","---------")
       }
       printf(" %11s\n","===========")
    
       for (i=0; i<COL; i++) {
          printf("%10d ",ttl_tate[i])
       }
       printf("%12d\n",ttl_tate[COL])
    # 平均を求めて出力
       for (i=0; i<COL; i++) {
          printf("%10d ",ttl_tate[i]/lno)
       }
       printf("%12d\n",ttl_tate[COL]/lno)
    }