awk入門 コマンドの使い方とスクリプトの書き方

AWKとは、文字列の検索、抽出、変換及び置き換えに長けたプログラミング言語です。おもにテキストファイルから一部分を抜き出したり、書式を変換するのに使われます。

AWKのインストール方法

Unix

たいていのLinuxには、あらかじめawkがインストールされている。ただし、awkより高機能なGNU版awk「gawk」をインストールすることもできる。

Microsoft Windows

Microsoft WindowsではGNU版awkであるgawkを使用できる。gawkのインストール方法を示す。

  1. ウェブブラウザでGawk for Windowsを開く。
  2. 「Complete package, except sources」の「Setup」をクリックする。
  3. 自動的にインストーラのダウンロードが始まる。
  4. ダウンロードしたインストーラを実行する。
  5. Gawk for Windowsがインストールされる。
  6. 環境変数のPATHにGawk for Windowsの実行ファイルフォルダ(C:\Program Files (x86)\GnuWin32\bin)を追加する。

awkコマンド

awkはファイルを走査し、指定したパターンのいずれかと一致する行を探します。一致する行が見つかったときに指定されたアクション(動作) を実行します。

実行形式には、スクリプトを引数として指定する方法と、スクリプトを格納したファイルの名前を引数で指定する方法があります。

スクリプトを引数として指定する場合、シェルからawkコマンドを次のように実行します。

awk 'スクリプト' [ 入力ファイルのパス ]

入力ファイルのパスは省略可能です。省略した場合は、標準入力が対象となります。

awkコマンドには次のオプションを指定できる。

-f path

あらかじめスクリプトを格納したテキストファイルを作成しておき、そのスクリプトファイルの名前を引数で指定する方法の場合、シェルからawkコマンドを次のように実行する。

awk -f スクリプトファイルのパス [ 入力ファイルのパス ]

スクリプトファイルの拡張子にとくに決まりはない。

-F field-separator

入力のフィールド区切り文字を指定する。

$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
$ awk -F: '{print $3, $1}' /etc/passwd
0 root
1 daemon
2 bin

gawkコマンド

gawkコマンドはGNU版のAWKである。LinuxやWindowsなどさまざまなOSで使うことができる。

スクリプトをgawkコマンドの引数に指定して実行する場合の構文は次のとおり。

gawk [options] [--] 'program-text' [file ...]

あらかじめスクリプトを記述したファイルを用意しておき、gawkコマンドの引数にそのファイルパスを指定して実行する場合の構文は次のとおり。

gawk [options] -f program-file [--] [file ...]

program-text にはawkのプログラムを指定する。

gawkに指定できるオプションを示す。

-F field-separator
入力のフィールド区切り文字を指定する。
-f program-file
awkのプログラムファイルを指定する。
$ gawk -f example.awk example.csv

パターンとアクション

スクリプトはテキストの置換・抽出・変換などのルールを指定するもので、パターン文とアクション文から成り立ちます。スクリプトは次の形式で記述します。

pattern { action }

入力行をパターンと比較して一致したら、アクション文を実行します。 パターンは正規表現で記述することができます。

awk '/井上/ { print $0 }' 住所録

上記の例では、住所録ファイル内で「井上」という文字列を含む行を出力しています。

パターン

パターンは次の3種類で表します。

任意の文字列を正規表現で表すことができます。

/RegularExpression/

行の末尾は $ で表します。たとえば、最後が na で終わる行は na$ と表せます。

$ cat students.txt
Shiratori Sana
Nonaka Kokona
Tanaka Miku
Yagi Miki
Sato Neo
Todaka Miko
Nozaki Yume
Kimura Sakia
$ awk '/na$/ { print $0 }' member
Shiratori Sana
Nonaka Kokona
$

BEGIN

特別なパターンとして、BEGINがあります。BEGINパターンのアクションには、最初の行を読み込む前に実行する処理を記述します。

BEGIN {
  print "*** start ***"
}
{
  print $0
}

END

特別なパターンとして、ENDがあります。ENDパターンのアクションには、最後の行を読み込んだ後に実行する処理を記述します。

{
  print $0
}
END {
  print "*** end ***"
}

区切り文字

awkコマンドにおけるデフォルトの区切り文字はスペース(空白文字)である。

区切り文字を指定するには、次に示す2通りの方法がある。

awkの組み込み変数

awkにはあらかじめ定義されている組み込み変数がある。

awkの組み込み変数
組み込み変数 説明 デフォルト値
FILENAME 現在の入力ファイル名 "-"
RS 入力のレコード区切り文字 改行(\n)
FS 入力のフィールド区切り文字 スペース
ORS 出力のレコード区切り文字 改行(\n)
OFS 出力のフィールド区切り文字 スペース
NR 現在のレコード数
NF 現在のレコードのフィールド数
$0 現在の入力レコード
$n 現在の入力レコードにおけるn番目のフィールド

awkの変数

awkにおける変数の命名規則は次のとおり。

変数に値を代入するには「=」を使う。

BEGIN {
  x = 10
  y = "foo"
  print x
  print y
}

配列

awkでは配列を使うことができる

BEGIN {
  z[1] = 1
  z[2] = 2
  print z[1]
  print z[2]
}

連想配列

awkでは連想配列を使用できる。

$ cat order.txt
apple 10
grape 3
orange 5
apple 7
orange 3
$ cat order.awk
{ order[$1] += $2 }
END {
  for (x in order) print x " " order[x]
}
$ gawk -f order.awk order.txt
apple 17
orange 8
grape 3
$

AWKの組み込み関数

AWKには次表に示す組み込み関数がある。

AWKの組み込み関数
関数 説明
cos 余弦(コサイン)を返す。
exp 指数を返す。
getline 次のレコードを読み込む。
index 指定した文字列が最初に出現する位置を返す。
int 小数点以下を切り捨てた整数を返す。
length 文字列の長さ(文字数)を返す。
log 自然対数を返す。
match 指定した正規表現が最初に出現する位置を返す。
sin 正弦(サイン)を返す。
split 文字列を配列要素に分解して、その要素数を返す。
sprintf 書式に従って文字列に変換する。
sqrt 平方根を返す。
substr 部分文字列を返す。

cos

余弦(コサイン)を返す関数です。

number cos(number)

exp

指数を返す関数です。

number exp(number)

exp関数の使用例を以下に示す。

$ cat naturalnumber.txt
1
2
3
4
5
$ awk '{print $1, exp($1)}' naturalnumber.txt
1 2.71828
2 7.38906
3 20.0855
4 54.5982
5 148.413

getline

number getline()

現入力ファイルの次のレコードを組み込み変数 $0 に設定します。getline 関数は正常終了時には1を、ファイルの終わりに達すると0を、エラー発生時には-1を返します。

index

number index(string, substring)

文字列 string の中で文字列 substring が最初に出現する位置を返します。出現しなければ0を返します。

int

小数点以下を切り捨てた整数を返す関数です。

number int(number)
number int(string)

length

引数で指定した文字列の長さ(文字数)を返す。

number length([string])
string
長さ(文字数)を調べる文字列を指定する。stringの指定を省略した場合、$0(レコード全体)の長さが返る。

log

自然対数を返す関数です。

number log(number)

log関数の使用例を以下に示す。

$ cat naturalnumber.txt
1
2
3
4
5
$ awk '{print $1, log($1)}' naturalnumber.txt
1 0
2 0.693147
3 1.09861
4 1.38629
5 1.60944

match

awk

match(string, regexp)

gawk

match(string, regexp[, array])

文字列stringの中で正規表現regexpが最初に出現する位置(1~)を戻り値として返す。regexpにマッチする文字列が存在しなければ戻り値として0を返す。

sin

number sin(number)

number の正弦(サイン)を返す関数です。

split

number split(string, array, fs)

文字列 stringarray[1]array[2]、...、array[n] の配列要素に分割して、値 n を返します。この分割は正規表現fs によって行われ、fs が指定されていない場合はフィールドセパレータによって行われます。

$ cat split.txt
foo:bar baz:qux
$ cat split1.awk
{
  n = split($0, a)
  print n
  for (i in a) {
    print a[i]
  }
}
$ awk -f split1.awk split.txt
2
foo:bar
baz:qux
$ cat split2.awk
{
  n = split($0, a, ":")
  print n
  for (i in a) {
    print a[i]
  }
}
$ awk -f split2.awk split.txt
3
foo
bar baz
qux
$

sprintf

string sprintf(format, expr, expr, ...)

format で指定した printf 形式に従って式の書式を定め、文字列を返します。

sqrt

number sqrt(number)

number の平方根を返す関数です。/p>

sqrt関数の使用例を以下に示す。

$ cat naturalnumber.txt
1
2
3
4
5
$ awk '{print $1, sqrt($1)}' naturalnumber.txt
1 1
2 1.41421
3 1.73205
4 2
5 2.23607

substr関数

string substr(string, m[, n])

文字列 string 内の m 番目から始まる長さ n の部分文字列を返します。

tolower

文字列を小文字に変換する。

tolower(string)

tolower関数の使用例を次に示す。

$ cat authors.txt
Charles Dickens
William Shakespeare
$ awk '{print tolower($0)}' authors.txt
charles dickens
william shakespeare

toupper

文字列を大文字に変換する。

toupper(string)

toupper関数の使用例を次に示す。

$ cat authors.txt
Charles Dickens
William Shakespeare
$ awk '{print toupper($0)}' authors.txt
CHARLES DICKENS
WILLIAM SHAKESPEARE

ユーザ定義関数

awkではユーザが独自の関数を定義することができる。関数の定義は次の書式で記述する。

function name([parameter[,parameter...]]) {
  statements
  return expr
}

awkにおける関数の引数は値渡しである。参照渡しにすることはできない。ただし、awkの変数はすべてグローバル変数なので、関数内で設定した変数を関数の外で参照できる。また、関数の外で設定した変数を関数内で参照できる。

関数の呼び出しは次の書式で記述する。

name([argument[,argument...]])

awkの関数は再帰呼び出し(関数の中でその関数自身を呼び出す)も可能である。

awkの演算子

比較演算子

awkの比較演算子
比較演算子 説明
expr1 == expr2 expr1expr2が等しい
expr1 != expr2 expr1expr2が等しくない
expr1 < expr2 expr1expr2より小さい
expr1 <= expr2 expr1expr2以下
expr1 > expr2 expr1expr2より大きい
expr1 >= expr2 expr1expr2以上

論理演算子

awkの論理演算子
論理演算子 説明
expr1 && expr2 論理積
expr1 || expr2 論理和
!expr 否定

アクション

アクションは一連の文です。使用できる文は次のうちのいずれかです。

コマンド 説明
break if、while、do、for の処理を中止する。
continue 現在の繰り返し処理を中断して、次の繰り返し処理にスキップする。
delete 配列のキーと値を削除する。
do 反復処理(後判定)
exit 残りの入力を飛ばして、ENDアクションを実行する。
for 反復処理
if 条件分岐
next 現在の入力レコードの処理を終了して、次の入力レコードに進む。
print 標準出力に出力する。
printf 書式にしたがって文字列に変換し、標準出力に出力する。
while 反復処理(前判定)

if

ifは条件分岐を行う制御構文である。

if (condition) then-body [else else-body]

conditionには条件式を指定する。条件式には比較演算子や論理演算子を使うことができる。

if (x % 2 == 0)
print "xは偶数です。"
else
print "xは奇数です。"

改行を入れずに1行で記述することもできる。ただし、この場合はthen-bodyとelseをセミコロンで区切る必要がある。

if (x % 2 == 0) print "xは偶数です。"; else print "xは奇数です。"

while

AWKのwhile制御文は、条件が真の間、処理を繰り返す。

while (condition) statement
while (condition) { statements }
condition
繰り返しを続行する条件を指定する。条件が真である間、処理を繰り返す。whileループは処理を実行する前に繰り返し条件をチェックする前判定である。つまり、一度も処理を実行しないこともある。

do

AWKのdo制御文は、処理を実行して、条件が真であればさらに処理を繰り返す。

do statement while (expression)
do { statements } while (expression)
condition
繰り返しを続行する条件を指定する。条件が真である間、処理を繰り返す。doループは処理を実行した後に繰り返し条件をチェックする後判定である。つまり、必ず一度は処理を実行する。

for

AWKのfor制御文は、変数を初期化して、条件が真の間、処理を繰り返す。次の繰り返し処理を行う際、変数の値を変化させることができる。

for (initialization; condition; increment) statement
for (initialization; condition; increment) { statements }
for (var in array) statement
for (var in array) { statements }
initialization
繰り返し処理を始めるときに一度だけ実行する処理を指定する。大抵は、ループカウンタの初期化を行う。
condition
繰り返しを続行する条件を指定する。たいていはループカウンタが上限値を超えていないことのチェックである。条件が真である間、処理を繰り返す。forループは処理を実行する前に繰り返し条件をチェックする前判定である。つまり、一度も処理を実行しないこともある。
increment
次の繰り返しに移るたびに実行する処理を指定する。大抵は、ループカウンタのインクリメント(+1)またはデクリメント(-1)である。
for (i in a) {
  delete a[i]
}

printfを用いたAWKのサンプルを示す。

$ cat factorial.txt
1
3
5
$ cat factorial.awk
{
f = 1
for (i = 2; i <= $1; i++) {
  f = f * i
}
print $1 "の階乗は" f
}
$ awk -f factorial.awk factorial.txt
1の階乗は1
3の階乗は6
5の階乗は120
$

break

while、do、for の繰返し処理を中止する。

break

continue

現在の繰り返し処理を中断して、次の繰り返し処理にスキップする。

continue

print

標準出力に出力する。

print [expr [expr]...] [>|>> filename]
print [expr [,expr]...] [>|>> filename]
expr
標準出力に出力する式を指定する。exprを省略した場合は現在のレコード($0)を出力する。出力されるレコードの最後にはORSの値が付加される。

expr を空白で区切って複数指定した場合、連結されて出力される。たとえば、 print "a" "b" "c"print "abc" と同じである。

expr をカンマで区切って複数指定した場合、空白で区切られて出力される。たとえば、 print "a", "b", "c"print "a b c" と同じである。

filename
出力をリダイレクトする場合、リダイレクト先を指定する。

ファイルfoo.txtへ出力する例を示す。

print "Hello, world!" > foo.txt

ファイルfoo.txtへ追加出力する例を示す。

print "Hello, world!" >> foo.txt

printf

printfは、書式にしたがって文字列に変換し、標準出力に出力する。

printf format [,expr...] [>|>> filename]
format
書式を指定する。書式にはメタ文字を使用できる。
printfのメタ文字
メタ文字 説明
%c ASCIIの1文字
%d 整数
%nd n桁の整数
%0nd n桁の整数(桁数がnに満たない場合は0で埋める)
%f 浮動小数点
%e 指数形式
%o 符号なし8進数
%s 文字列
%ns n桁の文字列
%% 「%」という文字そのもの
expr
書式で使用する値。リテラル、変数、関数又は計算式などを指定する。
$ cat printf.txt
65 foo
$ cat printf.awk
{printf "%c %d %04d %f %e %o %s %%", $1, $1, $1, $1, $1, $1, $2}
$ awk -f printf.awk printf.txt
A 65 0065 65.000000 6.500000e+01 101 foo %
$

next

next

現在の入力レコードの処理を終了して、次の入力レコードに進む。

exit

残りの入力を飛ばして、ENDアクションを実行する。ENDアクションの中でのexitステートメントでは、さらにENDアクションが呼び出されることはない。

exit [ 終了ステータス ]

delete

deleteステートメントは、配列のキーと値を削除する。

delete array[expr]
for (i in a) {
delete a[i]
}

関連コマンド

sed

$0

組み込み変数 $0 は、入力行(レコード)を表します。

$n

組み込み変数 $n は、n番目のフィールドを表します。

最初の2フィールドを逆順に出力する例を次に示す。

$ cat students.txt
Shiratori Sana
Nonaka Kokona
Tanaka Miku
Yagi Miki
Sato Neo
Todaka Miko
Nozaki Yume
Kimura Sakia
$ awk '{ print $2, $1 }' students.txt
Sana Shiratori
Kokona Nonaka
Miku Tanaka
Miki Yagi
Neo Sato
Miko Todaka
Yume Nozaki
Sakia Kimura

FILENAME

組み込み変数 FILENAME は、現入力ファイル名を表します。

$ awk '{print FILENAME}' foo.txt
foo.txt
$

FS

組み込み変数 FS は、各レコードにおけるフィールドの区切り文字 (field separator) を正規表現で表したものである。

FS の初期値は空白文字である。

入力ファイル /etc/passwd からユーザIDとユーザ名を出力する例を示す。

$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
$ awk 'BEGIN{FS=":"}{print $3,$1}' /etc/passwd
0 root
1 daemon
2 bin

NF

組み込み変数 NF は、現レコード中のフィールド数を表します。

NR

組み込み変数NRは、現レコード番号を表します。

特別パターン END においては現レコード番号は最後のレコード番号となりますので、つまり全レコード数(入力ファイルの行数)となります。

行番号と入力行を出力するawkスクリプトの例を示す。

$ cat students.txt
Shiratori Sana
Nonaka Kokona
Tanaka Miku
Yagi Miki
Sato Neo
Todaka Miko
Nozaki Yume
Kimura Sakia
$ awk '{ print NR, $0 }' students.txt
1 Shiratori Sana
2 Nonaka Kokona
3 Tanaka Miku
4 Yagi Miki
5 Sato Neo
6 Todaka Miko
7 Nozaki Yume
8 Kimura Sakia

2番目のフィールドを合計して、合計値と平均値を出力するAWKのサンプルを示す。

$ cat foo.txt
foo 30
bar 50
baz 100
$ cat foo.awk
{ sum += $2 }
END {
print "合計値", sum
print "平均値", sum / NR
}
$ awk -f foo.awk foo.txt
合計値 180
平均値 60
$

OFMT

組み込み変数 OFMT は、数値の出力形式を表します。

OFS

組み込み変数 OFS は、出力フィールドセパレータを表します。

ORS

組み込み変数 ORS は、出力レコードセパレータを表します。

RS

組み込み変数 RS は、入力レコードのセパレータ(区切り文字)を表す。

CSVのヘッダを読み飛ばす

CSVの1行目にあるヘッダを読み飛ばすには、NR が2以上のパターンに対してアクションを起こすようにする。

NR>1 {
# 処理
}