satoshiabe.jp : Introduction to AWK

HOME > DOCUMENTS > PROGRAMMING > AWK > Introduction to AWK

Introduction to AWK

Updated : 2006/05/10
Created : 2006/01/18

まえがき

AWK とは

なぜ AWK を学ぶのか?

AWK の実行

AWK の構文

フィールド

BEGIN | MAIN | END

実行の種類

AWK の変数

フロー制御 : if 文

フロー制御 : while 文

フロー制御 : for 文

next 文

演算子 : in

配列

連想配列

split 関数

length 関数

substr 関数

index 関数

sub 関数と gsub 関数

system 関数

getline 関数

rand 関数と srand 関数

shell スクリプトの引数を AWK で処理する

外部ファイルに書き込む

ビルトイン変数 ARGC, ARGV

ビルトイン変数 FS

ビルトイン変数 NF

ビルトイン変数 FILENAME

ビルトイン変数 NR

User-Defined function

複行レコード

連想配列で 2 つのファイルの各行を比較するスクリプト

リンク

まえがき

このページは、自分用の AWK 備忘録として作成した。 もしかしたら AWK を学ぼうとする人に役立つかもしれない、ということを意識しつつ、徐々に内容を充実させる予定。 いずれにしても、すべてを説明できるわけではないため、詳細な情報を確認するなら、公式のドキュメントを参照してほしい。 なるべく、参考になりそうなスクリプトをサンプルとして説明している。

AWK とは

Interpreter 方式のプログラミング言語。 実行する前にコンパイルしなくて良いため、すぐに結果を確認できる。 shell でスクリプトを作成していて shell が実装している機能のみでは対応できない場合など、とても重宝する。

AWK が得意とする対象は、構造化されているレコードだ。 AWK に処理させようとしている内容が構造化されていない場合、処理が複雑になる、あるいは、AWK では処理できないかもしれない。

構造化されているレコード

name country state chity yamada japan tokyo shinagawaku hanako japan tokyo minatoku

構造化されていないレコード

AWK はとても便利で簡単だがプログラミングしたことの ない私のような人にとってはなかなか難しかったりする。

なぜ AWK を学ぶのか?

私が AWK を学んだ理由は、必ずしも他の人が AWK を学ぶ理由と一致しない。 私は shell で複雑なテキスト処理をするようになってからというもの、shell が実装している機能のみでは苦しい場面が多くなっていることを実感していた。 実際、「高度なテキスト処理をしたいのなら Perl でしょう」と私は言われた。 ただし、私の実力から判断すると、Perl で実用的なスクリプトを書くまで時間がかかることが容易に推測できた。 なぜなら、これまでに私はいくつかの言語を習得しようとして挫折してきたからだ。 個人的な感想だが、AWK は Perl と比較して敷居が低い。 また、覚えたての機能を shell スクリプトにも組み込みやすい。 AWK を学習することによってプログラミングの基礎知識を養うことができる、という情報を得ていたこともあり、まずは shell + sed + AWK で shell 単体のときよりも高度なテキスト処理をできるようになろうと考えた。 今となっては AWK でスクリプトを書くことは少なくなりつつあるが、時間が限られている場合やプロトタイプ的なスクリプトを作成するときには、依然として AWK を利用している。

AWK の実行

まずは AWK を実行してみる。 コマンドラインで AWK を実行する場合、続く命令をクォートする必要がある。 ふたつめの引数では、処理するファイルを指定している。

この短いコマンドを実行すると、/etc/passwd の情報が画面に表示されるはずだ。 AWK は、ファイルから 1 行 1 行を読み込んで、その読み込んだ行に対して、指定した命令を実行する。 サンプルの場合、print コマンドのみをしていしているので、読み込んだ 1 行をそのまま表示しているだけだ。

% awk '{ print }' /etc/passwd

AWK は、引数に指定されたファイルから読み込むが、引数にファイルが指定されなかった場合、標準入力から読み込もうとする。

AWK の構文

以下は、AWK を実行するための基本的な構文だ。

pattern { action statements }

pattern は、各入力レコードに対してマッチングが実行される。 マッチすれば、続いて { action statements } が実行される。

尚、pattern と action statements を、どちらか一方だけ省略できる。 pattern を省略した場合、全ての入力行で action statements が実行される。 action statements が省略された場合、pattern にマッチすれば { print } が実行される。 print は print $0 と等価だ。 つまり、入力行すべてを print する。

pattern の指定にはいくつかの種類がある。 それぞれについては、サンプルで例を挙げつつ説明する。

BEGIN END /regular expression/ relational expression pattern && pattern pattern || pattern pattern ? pattern : pattern (pattern) ! pattern pattern1, pattern2

フィールド

AWK には、「フィールド」という概念がある。 これは、ビルトイン変数 FS に設定されている文字を separator として区切られた入力行のことだ。

ビルトイン変数 FS の初期値は、「1 つのスペース」だ。 そのため、以下のケースでは、行が aaa から eee まで 5 つのフィールドに分割されて処理される。 尚、明示的に指定すれば、ビルトイン変数 FS の値を変更できる。

% cat alice aaa bbb ccc ddd eee

このファイル alice の例で説明すると、第 1 フィールド aaa を $1、第 2 フィールド bbb を $2、...第 n フィールドを $n として指定できる。 入力行の全てを指定するために $0 が用意されている。

% chmod 755 awkscr % cat awkscr #!/usr/bin/awk -f { print "\$1 is " $1 print "\$2 is " $2 print "\$0 is " $0 } % % ./awkscr alice $1 is aaa $2 is bbb $0 is aaa bbb ccc ddd eee %

BEGIN | MAIN | END

AWK には、BEGIN ルール、MAIN ループ、END ルールという機能がある。

BEGIN { action statements } で指定された BEGIN ルールは、すべてのファイルを読み込む前に実行される。

{ action statements } で指定された MAIN ループは、ファイルの各行が読み込まれるたびに実行される。

END { action statements } で指定された END ルールは、MAIN ループが終了した後に実行される。

BEGIN { ### ファイルが読み込まれる前に実行される } { ### ファイルが読み込まれて 1 行ごとに実行される } END { ### ファイルが読み込まれた後に実行される }

実行の種類

AWK を実行する方法には、いくつか種類がある。 単純な処理の場合、コマンドラインからでも十分だ。 複雑な処理の場合、AWK プログラムのファイルを用意すると良いだろう。

ひとつめ : コマンドラインで実行する。 shell が誤解しないよう ' を忘れずに。

% awk '{ print }' list.txt

ふたつめ : -f オプションで AWK スクリプトを指定し、その後の引数にファイルを指定して実行する。

% cat awkscr BEGIN{ print "hoge" } { print } END { print "fuga" } % % awk -f awkscr list.txt

みっつめ : AWK スクリプトに実行権限を付与し、直接スクリプトを実行する。

% chmod 755 awkscr % cat awkscr #!/usr/bin/awk -f BEGIN{ print "hoge" } { print } END { print "fuga" } % % ./awkscr list.txt

AWK の変数

AWK において、変数に値を代入するとき、また変数の値を参照するとき、変数の文字列だけを書くこと。 具体的な例として、shell の場合、変数に値を代入するときは var=hoge で 変数の値を参照するときは $var だ。 ただし、AWK の場合、代入するときも参照するときも、変数の頭に何か文字列を記述する必要しなくて良い。 変数に値を代入するとき、値が文字列ならクォーティングすること。

% chmod 755 awkscr % cat awkscr #!/usr/bin/awk -f BEGIN { foo = "hoge" print foo var = 2 print var } % % ./awkscr hoge 2 %

フロー制御 : if 文

if 文の構文は以下のとおり。

if (condition) statement [ else statement ]

MAIN ループの中で if 文を使用するサンプル。 /^root/ は正規表現で、行頭に root という文字列があったら true となり、続くブレース {} 内部の処理が実行される。

% chmod 755 awkscr % cat awkscr #!/usr/bin/awk -f { if (/^root/) { print } } % % ./awkscr /etc/passwd

尚、上のスクリプトで expression の結果を反転させたい (つまり /^root/ でなければという意味にしたい) 場合、以下のように ! を使用する。

% chmod 755 awkscr % cat awkscr #!/usr/bin/awk -f { if (! /^root/) { print } } % % ./awkscr /etc/passwd

また、以下のスクリプトを実行しても同様の結果を得られる。 action statements が省略されているため、print 文が実行されている。

% cat awkscr #!/usr/bin/awk -f /^root/

反転させた例。

% cat awkscr #!/usr/bin/awk -f ! /^root/

フロー制御 : while 文

while 文の構文は以下のとおり。

while (condition) statement

while 文では、条件の condition が true であればループを実行、false であればループを終了する、という処理をする。 尚、以下の例ではスクリプトに引数を与えずに awk の試験をするため、全て BEGIN ルール内に記述している。

% chmod 755 awkscr % cat awkscr #!/usr/bin/awk -f BEGIN{ i=0 while (i < 10) { print i i++ } } % % ./awkscr 0 1 2 3 4 5 6 7 8 9 %

フロー制御 : for 文

for 文の構文は以下のとおり。

for (expr1; expr2; expr3) statement

for 文を使用した簡単なサンプルをひとつ。

% chmod 755 awkscr % cat awkscr #!/usr/bin/awk -f BEGIN{ for (i=0; i<=9; i++) { print i } } % % ./awkscr 0 1 2 3 4 5 6 7 8 9

next 文

現在のレコードに対する処理を終了し、次のレコードを読み込む。 MAIN ループの最初のパターンから処理が開始される。

next

たとえば、以下のようなファイルが存在したとしよう。

% cat list.txt aaa bbb ccc %

そこで、以下のような AWK スクリプトを実行すると...、

% chmod 755 awkscr % cat awkscr #!/usr/bin/awk -f { if (/^a+/) { print "I found 'a'" } print "POINT1" if (/^b+/) { print "I found 'b'" } print "POINT2" if (/^[^ab]+/) { print "I did not found 'a or b'" } print "POINT3" }

このように実行される。

% ./awkscr list.txt I found 'a' POINT1 POINT2 POINT3 POINT1 I found 'b' POINT2 POINT3 POINT1 POINT2 I did not found 'a or b' POINT3 %

登場したパターンをそれ以降の処理に移行させないようにしたい場合がある。 サンプルのスクリプトでは、、if 文が連続で出現している。 1 回、出現したパタンがそれ以降は出現しないとわかっている場合などがある。 具体的には、/a+/ というパタンがファイルが出現したら以降 /^a+/ というパタンが出現しない場合、それ以降の /^b+/ や /^[^ab]+/ を処理するのは時間の無駄になる。

そこで next 文を登場させる。 わかりやすいように print "" で改行させている。

% chmod 755 awkscr % cat awkscr #!/usr/bin/awk -f { if (/^a+/) { print "I found 'a'" print "" next } print "POINT1" if (/^b+/) { print "I found 'b'" print "" next } print "POINT2" if (/^[^ab]+/) { print "I did not found 'a or b'" print "" next } print "POINT3" print "" } %

以下のように実行されるようになる。 /^a+/ も /^b+/ も、スクリプトに検出された後、それ以降に処理されていないことを確認できる。

% ./awkscr list.txt I found 'a' POINT1 I found 'b' POINT1 POINT2 I did not found 'a or b' %

演算子 : in

演算子 in を使用することによって、配列のメンバを確認できる。

item in array

演算子 in を使用することによって、配列のメンバを確認できる。

item = "hoge" if (item in array) { print "array[itmp] exists." }

配列

AWK は 1 次元配列を扱える。 構文は以下のとおり。

代入

array[n]=value

参照

array[n]

NR は、現在の入力行の数を保持しているビルトイン変数だ。 以下の例では、インデックスを 0 か順に配列の値にして、ファイルの各行の第 1 フィールドを配列に入力している。 参照は for 文で。

#!/usr/bin/awk -f { array[NR]=$1 } END { for (i=1; i<=NR; i++) { print i "\t" array[i] } }

連想配列

AWK では連想配列を扱える。

代入

array[key]=value

参照

array[key]

sh や bash では連想配列を扱えないので、覚えておくとスクリプト作成の幅が広がる。 ただし、Perl と異なり大きな連想配列を扱うと処理が重くなる、という事実を知っておくこと。

% cat awkscr BEGIN { FS = ":" } /[a-z]+/ { array[$1] = $0 } END { for (item in array) { print item "\t\t" array[item] } } % % /usr/bin/awk -f awkscr /etc/passwd

サンプルでは、BEGIN ルール内で FS 変数を : に変更している。 後述するが、FS 変数はフィールドセパレータの情報を保持している。 コマンドラインであれば、以下のように -F オプションでフィールドセパレータを指定したりもする。 ただし、スクリプトを作成するのであれば、BEGIN ルール内で指定 (他のビルトイン変数も) すると便利だ。

% awk -F":" '{print $1}' /etc/passwd

split 関数

split 関数は、入力した行 string を separator で分割し、配列 array に格納する。 string を変数で指定しても良い。 n には分割したフィールド数が保存される。 正規表現で separetor を記述できる。

n = split(string, array, separator)

サンプルでは、split 関数で入力レコード $0 を、セパレータ \t として、配列 array に代入している。 分割したフィールド数を、変数 z に代入している。

{ z = split($0, array, "\t") for (i=1; i<=z; i++) { print i, array[i] } }

length 関数

length 関数は、文字列 s の長さを返す。 s を指定しなかった場合、$0 の長さを返す。

n = length(s)

サンプルでは、変数 foo に代入した 1 から 0 までの文字列を length 関数の引数とし、変数 num に返り値を代入している。

% chmod 755 awkscr % cat awkscr BEGIN { foo="1234567890" num=length(foo) print num } % % ./awkscr 10 %

substr 関数

substr 関数は、文字列 s の i 文字目から始まる最大 n 文字の部分文字列を返す。 n が省略された場合、 i 文字目以降の部分文字列が返される。

substr(s, i [, n])

サンプルは、コマンドラインから substr 関数を使用した例。

% echo "aaabbbcccddd" | awk '{ print $0 }' aaabbbcccddd % % echo "aaabbbcccddd" | awk '{ var = substr($0, 4); print var }' bbbcccddd % % echo "aaabbbcccddd" | awk '{ var = substr($0, 4, 3); print var }' bbb %

index 関数

index 関数は、文字列 s 中に含まれる文字列 t の位置を返す。 t が含まれていない場合は 0 を返す。

index(s, t)

サンプルは、コマンドラインから index 関数と substr 関数を使用した例。

% echo "aaabbbcccddd" aaabbbcccddd % echo "aaabbbcccddd" | awk '{ foo = index($0, "b"); print foo }' 4 % echo "aaabbbcccddd" | awk '{ foo = index($0, "b"); bar = substr($0, "4"); print bar }' bbbcccddd %

サンプルをもうひとつ。

% echo "aaabbbcccddd" | awk ' { foo = index($0, "b") print "foo is: " foo bar = index($0, "c") print "bar is: " bar } END { hoge = substr($0, foo, bar - foo) print hoge }' foo is: 4 bar is: 7 bbb %

sub 関数と gsub 関数

sub と gsub は置換を処理する。 どちらも、指定した文字列を置換するが、置換した数を返す。 t を省略した場合、$0 が処理される。

sub(r, s [, t]) gsub(r, s [, t])

サンプルのスクリプト。 置換した数を返すので、実際に文字列を置換しているものの、数値が表示されている。 置換された文字列を表示する場合、以下のように if 文を使用して表示させたりする。

% cat awkscr #!/usr/bin/awk -f BEGIN { FOO = "abc000abc" NUM_FOO = gsub(/[a-z]/, "Z", FOO) print FOO FOO = "abc000abc" print FOO if (gsub(/[a-z]/, "Z", FOO)) { print FOO } } % % ./awkscr 6 ZZZ000ZZZ abc000abc ZZZ000ZZZ %

尚、gsub の g はレコードに対してグローバル (g) に作用することを意味している。 そのため、sub 関数は、グローバルではなく文字列の最初の文字だけに作業する。 そのため、返り値は 0 か 1 のみとなる。

system 関数

system(cmd-line)

system 関数は、cmd-line で指定されたコマンドを実行し、そのコマンドの終了ステータスを返す。 サンプルのスクリプトでは、system 関数の引数として、shell の test コマンドを実行し、ファイルに読み込み権限が付与されているかを確認している。

% cat awkscr #!/usr/bin/awk -f BEGIN{ if (system("test -r hoge") == 0) { print "readable" } else { print "file is not readable" } } %

getline 関数

AWK で外部コマンドを実行する方法。 getline 関数は次の行を読み込む。 新しい行を読み込めなくなると while の条件 false になるのでループ処理を終了する。 おそらく、容量の多いファイルを cat すると、読み込みに時間がかかるだろうから

BEGIN { while ("cat /etc/passwd" | getline) { print } }

getline を使用してファイルの中身を読み込む場合、以下の方が良い。

BEGIN{ while((getline < "/etc/passwd") > 0) { print } }

rand 関数と srand 関数

rand 関数は、0 から 1 間での間の数を生成する。 srand 関数は、乱数生成関数 rand の種として使用される。

rand 関数の例。

% awk 'BEGIN { print rand() }' 0.237788 % awk 'BEGIN { print rand() }' 0.237788 % awk 'BEGIN { print rand() }' 0.237788 % awk 'BEGIN { print rand() }' 0.237788 % awk 'BEGIN { print rand() }' 0.237788

srand 関数の例。

% awk 'BEGIN { print srand() }' 1 % awk 'BEGIN { print srand() }' 1 % awk 'BEGIN { print srand() }' 1 % awk 'BEGIN { print srand() }' 1 % awk 'BEGIN { print srand() }' 1 %

rand 関数と srand 関数を使用した例。

% awk 'BEGIN { srand() ; print rand() }' 0.226184 % awk 'BEGIN { srand() ; print rand() }' 0.915806 % awk 'BEGIN { srand() ; print rand() }' 0.877775 % awk 'BEGIN { srand() ; print rand() }' 0.151561 % awk 'BEGIN { srand() ; print rand() }' 0.766849

rand 関数と srand 関数を使用した例。 awk に渡す引数が、当たっているか確認するスクリプト。

% cat awkscr #!/usr/bin/awk -f BEGIN { guess = ARGV[1] srand() var = rand() answer = int( var * 10 ) if (answer == guess ) { print "Congratulations!" } else { print "Incorrect answer" } } % ./awkscr 2 Incorrect answer % ./awkscr 2 Congratulations!

shell スクリプトの引数を AWK で処理する

オプション -v を使用する。

% cat sample #!/bin/sh awk -v first=$1 -v second=$2 ' BEGIN { print first print second }' $* % % ./sample aaa bbb aaa bbb %

外部ファイルに書き込む

通常、AWK の実行結果は、standard output へ送信される。 つまり標準出力のことだ。 ただし、スクリプトを作成していると出力をファイルに書き出したいときがある。 ファイルに書き出しておけば、後からでも内容を確認できるからだ。 結果をファイルに書き込む場合、> あるいは >> を指定する。 前者は上書きで後者は追記だ。

結果でファイルを上書きする場合、> を指定する。

BEGIN { ### これは上書きされる print "hoge hoge hoge" > "file.txt" }

結果をファイルに追記する場合、> を指定する。

BEGIN { ### これは追記される print "hoge hoge hoge" >> "file.txt" }

ビルトイン変数 ARGC, ARGV

ARGV は配列であり、コマンドラインの引数を保持している。 実際の引数は ARGV[1] からインデックスに 1 ずつ加えた ARGV[n] で参照できる。 ARGC では、引数の数を確認できる。

% chmod 755 alice % cat alice #!/usr/bin/awk -f BEGIN { print "ARGC is: "ARGC for (i=0; i<ARGC; i++) { print i "\t" ARGV[i] } } % % ./alice aaa bbb ccc ARGC is: 4 0 /usr/bin/awk 1 aaa 2 bbb 3 ccc %

以下のサンプルでは、引数の数をチェックしている。 スクリプトに 1 つ以上の引数を与えなかった場合、print でメッセージを表示した後、exit でスクリプトを終了する。

#!/usr/bin/awk -f BEGIN { if (ARGC < 2) { print "You must specify one arg at least." exit } } % % ./alice aaa bbb ccc % % ./alice You must specify one arg at least. %

ビルトイン変数 FS

FS 変数を BEGIN ルールの中で変更する。 FS 変数では、フィールドセパレータを指定できる。 デフォルトでは、単一の空白が設定される。

BEGIN { FS = ":" while ("cat /etc/passwd" | getline) { if (/^[a-z]/) { print $1 } } }

ビルトイン変数 NF

NF 変数は、現在の入力レコードのフィールド数を保持している。 この変数を使用したサンプルをひとつ。 score というファイルは、
名前 tab 点数 space 点数 space 点数 space 点数 space 点数
という構成になっている。 このファイルから、名前+合計得点+平均点を求める。 printf を使用すれば、より見やすくなるだろうが今回は print で。

% cat score hoge 10 20 30 40 50 fuag 15 25 35 45 55 foo 11 22 33 44 55 % % cat awkscr #!/usr/bin/awk -f { total = 0 for (i=2; i<=NF; i++) { total = total + $i } print $1 "'s score is:\t" total print $1 "'s average is:\t" total/(NF-1) } % % ./awkscr score hoge's score is: 150 hoge's average is: 30 fuag's score is: 175 fuag's average is: 35 foo's score is: 165 foo's average is: 33 %

以下のサンプルは、list ファイルに保存されている $2 から $n までの数値の中から最大値を抽出するスクリプト。

% cat list satoshi 10 20 30 15 45 25 50 25 % % cat awkscr #!/usr/bin/awk -f { ### $2 から $n までを配列に格納する for (i=2; i<=NF; i++) { array[i] = $i } ### 最大値を保持する変数 top に初期値を設定する top = $2 ### 比較して大きければ変数 top の値を上書きする for (i=3; i<=NF; i++) { if (array[i-1] < array[i]) { top = array[i] } ### 最大値を print する print $1"'s top score is: " top } % % ./awkscr list satoshi's top score is: 50 %

ビルトイン変数 FILENAME

FILENAME 変数を使用すると、AWK スクリプトに渡されるファイルの名前を確認し、その後の動作を変化させられる。

#!/usr/bin/awk -f FILENAME == "alice" { # ファイル名が alice であるときのみに実行される action print $0 }

ビルトイン変数 NR

ビルトイン変数 NR は、読み込んだ入力レコード数の合計を保持している。

% cat list.txt aaa bbb ccc ddd eee fff % % cat awkscr #!/usr/bin/awk -f { print NR, $0 } END { print "total: ", NR, "records exist." } % % ./awkscr list.txt 1 aaa 2 bbb 3 ccc 4 ddd 5 eee 6 fff total: 6 records exist. %

pattern で NR を使用すると、他にも使い道がある。

% awk 'NR>20 { print }' /etc/passwd % % awk 'NR==10,NR==20 { print }' /etc/passwd

User-Defined function

User-Defined function ( ユーザ定義関数 ) の機能により、繰り返し処理をしたい命令をモジュール化してまとめられ、再利用性が高まる。

function name(parameter-list) { body-of-function }

% cat awkscr #!/usr/bin/awk -f function func_total(arg1, arg2) { total = arg1 + arg2 print "total is: " total } BEGIN { while ((getline < "list") > 0) { func_total($1, $2) } } % % cat list Bob 10 20 Mike 30 40 Fred 50 60 Barney 70 80 Kathy 10 90 % % ./awkscr Bob total is: 30 Mike total is: 70 Fred total is: 110 Barney total is: 150 Kathy total is: 100 %

複行レコード

AWK は複行レコードを簡単に処理できる。 通常、セパレータで区切られた改行までの 1 行をレコードと呼ぶ。 ただし、複行レコードのテキスト処理をしたい場合、改行までではなく空行までの 1 ブロックをレコードとして認識してほしい。 改行をセパレータとして認識させる必要もある。 AWK では、FS を改行文字 "\n" に、RS を空文字 "" にセットすることだけで、空行を区切りとしたブロックを 1 レコードとして扱える。

サンプルのファイル。

% cat list.txt aaaaa aaaaa aaaaa aaaaa aaaaa bbbbb bbbbb bbbbb bbbbb bbbbb ccccc ccccc ccccc ccccc ccccc ddddd ddddd ddddd ddddd ddddd

以下のように作成して実行すると、

% cat awkscr BEGIN { FS = "\n" RS = "" } /^[ac].*/ { print $0 } % % /usr/bin/awk -f awkscr list.txt aaaaa aaaaa aaaaa aaaaa aaaaa ccccc ccccc ccccc ccccc ccccc %

連想配列で 2 つのファイルの各行を比較するスクリプト

少し実用的そうな、連想配列を使用してファイル A と ファイル B の行をそれぞれ比較するスクリプトを考えてみた。 以下のサンプルファイルを用意する。

% cat list0.txt aaa AAA bbb BBB ccc CCC ddd DDD eee EEE fff FFF % % cat list1.txt aaa AAA bbb BBB ddd DDD fff FFF

「ファイル list0.txt に存在する行がファイル list1.txt で存在しない場合、結果を result.txt に出力する。」という処理を連想配列を使用して実装する。 全てを BEGIN ルール内で処理している。

% cat awkscr #!/usr/bin/awk -f BEGIN { ### list1.txt を連想配列 array0 に格納 while ("cat list0.txt" | getline) { array0[$1]=$2 } ### list2.txt を連想配列 array1 に格納 while ("cat list1.txt" | getline) { array1[$1]=$2 } ### array0 からひとつずつ要素 item0 を取り出しつつ for (item0 in array0) { ### array1 に item0 が存在するか確認 if (item0 in array1) { print item0, "is found in array1" >> "result.txt" } else { print item0, "is NOT found in array1" >> "result.txt" } } ### result.txt に NOT が存在する行をカウント while ("cat result.txt" | getline) { if (/NOT/) { not_found++ } } print not_found, "line(s) did NOT exist." }

実行してみる。

% ./awkscr 2 line(s) did NOT exist. % % cat result.txt ddd is found in array1 ccc is NOT found in array1 bbb is found in array1 aaa is found in array1 eee is NOT found in array1 %

リンク

Manpage of GAWK

Effective AWK Programming

The GNU Awk User's Guide

Email to Satoshi ABE