awkのHello World

第4回は、awkによるHello Worldです。awkは、sedやPerlと同様、スクリプト言語の1つです。awkはPerlよりも軽量なので、awkでもPerlでも記述できるような処理は、awkで記述したほうが高速に動作するでしょう。

awkのHello Worldはリスト1の通りです。このように、awk文法のprintを使って、その引数に文字列を指定すれば、それがそのまま表示されます。

printでは、改行は自動的に付加されます。なお、awkスクリプトでは、プログラムをファイルから読み込むことを明示するため、-fオプションが必要です。

リスト1 printを使う方法(awk_print)

#!/usr/bin/awk -f        ← awkスクリプトであることを指定(-fオプションが必要)

BEGIN {                  ← BEGINのパターンに対応するアクションを開始
  print "Hello World"    ← printを使って文字列を出力(改行は自動)
}

awkスクリプトは、シェルスクリプトと同様に、実行例1のようにchmodコマンドで実行属性を付ければ実行できます。

実行例1 awkスクリプトの実行

$ chmod +x awk_print         ← awkスクリプトのファイルに実行属性を付ける
$ ./awk_print                ← awkスクリプトを実行
Hello World                  ← 確かにHello Worldが表示される
$                            ← シェルのプロンプトに戻る

awkは本来、標準入力(または引数指定の入力ファイル)から1行ずつ読み込み、何らかの加工を施して標準出力に出力するといった使い方が想定されています。このため、プログラムは「パターン { アクション }」の構造をしており、パターンには、正規表現や条件式などを使って、処理対象の行を指定します。パターンとしてBEGINを使うと、入力行を読む前にアクションが実行されます。したがって、Hello Worldのように入力行のないawkプログラムでは、パターンとしてBEGINのみを使うことになります。

なお、Solaris付属のawkは旧版のものであり、「BEGIN{}」しかないプログラムでも標準入力を読んでしまうとか、後述のsystem()が使えないなどの相違点があるため、SolarisではOS付属のnawkを代わりに使ってください。

printfを使う方法

awkにはprintfもあります。printfを使う場合はリスト2の通りで、printとは違って改行コード(\n)を付ける必要があります。

リスト2 printfを使う方法(awk_printf)

#!/usr/bin/awk -f

BEGIN {
  printf "%s\n", "Hello World"   ← printfを使って文字列を出力(改行が必要)
}

ところで、awkのprintやprintfは文法上のステートメントであって関数ではないため、「printf("Hello\n")」のように、( )を付ける必要はありません。しかし、( )を付けても、演算子の演算順序を指定するための括弧とみなされるだけなので、動作上は問題ありません。

コマンドラインから直接実行

プログラムをファイルから読むための-fオプションを付けずに、awkの引数にプログラムを記述し、コマンドラインなどから直接awkを実行することもできます。

実行例2は、前述のprintを使ったHello Worldを、コマンドラインから直接実行している例です。

実行例2 awkをコマンドラインから直接実行

$ awk 'BEGIN{print "Hello World"}'   ← コマンドラインでawkを直接実行
Hello World                          ← 確かにHello Worldが表示される
$                                    ← シェルのプロンプトに戻る

変数ORSを変更する方法

printでは、文字列の最後に改行コードが自動的に出力されますが、これは実は、awkのORS(Output Record Separator)という変数にデフォルトで改行コードがセットされているからです。

そこで、リスト3のように、ORS自体に文字列を代入し、空のprintを実行することで変わったHello Worldのプログラムができます。

リスト3 変数ORSを変更する方法(awk_ors)

#!/usr/bin/awk -f

BEGIN {
  ORS = "Hello World\n"      ← 変数ORSに直接メッセージを代入(改行つき)
  print                      ← 空のprintを実行
}

OSのコマンドを呼び出す方法

awkにはOSのコマンドを呼び出すsystem()関数があります。そこで、system()を使ってechoコマンドを呼び出すという方法も考えられます(リスト4)。

リスト4 OSのコマンドを呼び出す方法(awk_system)

#!/usr/bin/awk -f

BEGIN {
  system("echo 'Hello World'")   ← OS上のechoコマンドを実行
}

変則的なawkスクリプト

awkに-fオプションを付けずに、スクリプトの1行目の#!の右のawkコマンドに、直接awkプログラムを記述する方法で、変わったHello Worldを作成することができます。

リスト5は、そのような1行だけのスクリプトです。#!の行はカーネルに直接解釈されることと、OSによって若干解釈に違いがあることから、awkの引数のプログラム部分にはスペースを入れてはいけません。そこで、文字列を"Hello"と"World"に分け、それぞれをprintの別引数として「,」で区切って記述します。こうすると、「,」の部分に1個のスペース(変数OFSの内容)が挿入されます。

リスト5 引数に直接プログラムを記述する方法(awk_direct)

#!/usr/bin/awk BEGIN{print"Hello","World"}   ← 1行だけのawkスクリプト

リスト6は、ファイルにHello Worldを直接記述し、メッセージのある3行目だけをawkで抜き出すというものです。awkに-fオプションがないため、このファイルはプログラムではなく、awkへの入力ファイル(データ)となることに注意してください。

リスト6 指定行を抜き出す方法(awk_line)

#!/usr/bin/awk NR==3{print}     ← 3行目を抜き出すawkプログラムを1行で記述

Hello World                     ← ファイルの3行目にメッセージを直接記述

同じ発想で、メッセージを正規表現で抜き出すこともできます。リスト7は、正規表現で「#」以外で始まる空行以外の行を抜き出すという方式です。

リスト7 正規表現を使う方法(awk_regex)

#!/usr/bin/awk /^[^#]/{print}   ← 正規表現でメッセージを抜き出すawkプログラム
                                ← ここは空行
Hello World                     ← メッセージを直接記述