この章では,awk
コマンドについて説明します。awk
コマンドは,ファイル内のテキスト行を照合するためのツールであり,照合した行を操作するための一連のコマンドを提供しています。
awk
コマンドは,第 1 章で説明した拡張正規表現に従ってテキストを照合するだけでなく,各行すなわちレコードをフィールドの集合として扱い,各フィールドを個別にまたは組み合わせて処理することができます。
そのため,awk
コマンドを使用して,次のような複雑な操作を実行することもできます。
レコード内の特定のフィールドへの書き込み
レコードの内容の並び換え,または置き換え
たとえば,別のシステムに移行する際にプログラム・ソース・ファイル内の構文を変更したり,システム・コールを変更する場合などに使用します。
入力を処理し,数値の計算,合計または小計の算出を行う
所定のフィールドに数字情報だけが含まれていることを確認する
プログラミング・ファイル内でデリミタのバランスがとれていることを確認する
レコード内のフィールドに含まれるデータの処理
あるプログラムのデータを別のプログラムで使用可能な形式へ変更する
この章では,次の事項について説明します。
awk
プログラムの実行 (2.1 節)
awk
における出力 (2.2 節)
awk
変数の使用 (2.3 節)
パターンとしての正規表現 (2.4 節)
パターンとしての関係式および論理式 (2.5 節)
パターン・レンジの使用 (2.6 節)
awk
のアクション (2.7 節)
アクション内での演算子の使用 (2.8 節)
アクション内での関数の使用 (2.9 節)
awk
プログラムでの制御構造の使用 (2.10 節)
入力の処理前および処理後に実行するアクション (2.11 節)
文字列の連結 (2.12 節)
リダイレクションとパイプ (2.13 節)
awk
[
[-FERE
]
]
[
[-v var=val
]
]
{
[-f prog_file
]
| [prog_text
]
}
[ file1
[ file2 ...
]
]
表 2-1
に,awk
コマンドのフラグを説明します。
表 2-1: awk コマンドのフラグ
フラグ | 説明 |
-F ERE |
フィールド・セパレータとして使用する拡張正規表現を指定します。
省略時の設定では,
%echo $PATH | awk -F':' '{for(n=1;n<=NF;n++)print $n}'
|
-v var=val |
変数
var
に
val
を割り当てます。
このような割り当ては,プログラムの
BEGIN
ブロックに対してのみ有効です。
awk
コマンドでは,複数の
-v
フラグを指定することができます。 |
-f prog_file |
|
awk
プログラムは,-f
prog_file
フラグを使用してを実行することも,コマンド行にプログラムを記述して実行することもできます。
ファイル名の展開あるいは変数の代入が必要な場合は,コマンド行プログラムを引用符 ('
あるいは
"
) で囲みます。
一重引用符 ( ' '
) を使用し,-v var=val
オプションを使用して awk プログラムへシェル変数を引き渡すと,awk プログラムが読みやすくなります。
通常,awk
を実行する前に
awk
プログラム・ファイルを作成します。
プログラム・ファイルの内容は,次のような文の連続です。
pattern{
action}
pattern とは,照合するテキストを定義する 1 つまたは複数の式です。 パターンは次のものから構成されます。
BEGIN
または
END
論理演算子
!
(NOT),||
(論理 OR),および
&&
(AND) を使用した正規表現のブール演算の組み合わせ。
カッコを付けて,式をグループにまとめます。
関係演算式による文字列,数字,フィールド,および変数のブール演算の組み合わせ。
レコードの範囲。 次のように指定します。
pattern1,
pattern2
action
とは,awk
コマンド,オペランド,および演算子によって指定される,1 つまたは複数の処理です。
アクションは次のものから構成されます。
代入文
データのフォーマットおよびプリントを指定する文
制御の流れを選択するためのテスト
if-else
,while
,および
for
文などの制御構造
標準出力以外の,1 つまたは複数の出力ストリームへの出力リダイレクション
入出力のパイプ処理
中カッコ ( { }
) は,検索パターンとアクションを区別するためのデリミタです。
アクションは,1 行にまとめて指定しても,見やすいように複数行にまたがって指定してもかまいません。
複数のコマンドから構成されるアクションを 1 行で記述する場合は,セミコロンでコマンドを区切ります。
たとえば,次の 2 つのプログラムはどちらも,`Gunther' または `gunther' を含むすべてのレコードを検出します。awk
は,検出したすべてのレコードに関して,次のような 2 行の情報を出力します。
1 行目には照合したレコードの番号を,2 行目には照合したレコードの最初の 2 フィールドを出力します。
プログラム 1:
/[Gg]unther/ { print "Record:", NR ; print $1, $2 }
プログラム 2:
/[Gg]unther/ { print "Record:", NR print $1, $2 }
このプログラムからの出力は,次のようになります。
Record: 382 Schuller Gunther Record: 397 schwarz gunther
パターンおよびアクションはいずれも,プログラム行ではオプションの要素です。
パターンを省略した場合,awk
はファイル内のすべてのレコードにアクションを実行します。
アクションを省略した場合,awk
はレコードを標準出力にコピーします。
パターンとアクションの両方を省略した空プログラムの場合は,入力を変更しない状態で出力に渡します。
プログラム・ファイルを作成した後,次のように
awk
コマンドをコマンド行に入力してください。
$ awk -f progfile infile > outfile
このコマンドは,progfile
のプログラムを使用して,infile
を処理し,出力を
outfile
に書き込みます。
入力ファイルは変更されません。
プログラムが短い場合は,入力ファイル名の前にコマンド行上にプログラムを入力することによって,同じジョブを実行することができます。 たとえば,次のようにします。
$ awk '/[Gg]unther/ { print $1, $2 }' infile
この方法で awk を使用する場合は,一重引用符 ( ' '
) でプログラムを囲み,-v var=val
オプションを使用してすべてのシェル変数を引き渡します。
awk
を実行すると,awk
は,プログラムを読み取り,構文をチェックします。
次に,awk
は入力ファイルの最初のレコードを読み取り,パターンの出現順にプログラム・ファイルのそれぞれのパターンとレコードを突き合わせます。awk
が,レコードに照合するパターンを検出した場合は,awk
は対応するアクションを実行します。
次に
awk
は,プログラム・ファイルの中で照合を検索し続けます。awk
は,プログラム・ファイルのすべてのパターンに対して最初の入力レコードを突き合わせて,必要なすべてのアクションをレコードに実行した後,次の入力レコードを読み取り,そのレコードに対してプログラムを繰り返します。
このように,処理は入力ファイルの終わりまで継続されます。図 2-1
は,この順序のフローチャートです。awk
の動作と,図 3-1
で示した
sed
エディタの類似の動作とを比較してください。
図 2-1: awk 処理の順序
print
コマンドまたは
printf
コマンドを使用して,awk
で出力を生成することができます。
print
コマンドの構文では,引数をコンマまたは空白で区切ることができます。
コンマで区切られた引数は,現在の出力フィールド・セパレータ (OFS,省略時は空白) を使って出力されます。
空白で区切られた引数は,連結されて出力されます。
たとえば,次のようになります。
awk 'BEGIN{ x=22; print "ABC" x, "DEF" }' ABC22 DEF
printf( "
format",
value1[,
value2, ...] )
このコマンドは,format
文字列の定義に従って
value1,value2
などの引数をフォーマットし,出力します。
フォーマット指定子の構文については,
awk
(1)printf
(3)2.3 awk 変数の使用
awk
プログラムでは,情報を処理するために変数を使用します。
変数には次の 3 つのタイプがあります。
awk
言語は表 2-2
に示す組み込み変数をサポートしています。
また,上記の 3 つのタイプの変数は,作成したり変更したりすることもできます。
たとえば,次の代入文では,var
という名前の変数を作成しています。
変数の値は,現在のレコードの第 3 および第 4 フィールドを合計したものです。
var = $3 + $4
変数をパターンの一部として使用したり,その変数をアクションで処理したりすることもできます。
たとえば,次のプログラムは,変数
tst
に値を割り当て,以後のアクションのパターンの一部として
tst
を使用しています。
{ tst = $1 } tst == $3 { print }
2.3.1 項,2.3.2 項,および
2.3.3 項で,3 つのタイプの変数について説明します。
これらの項で使用する例では,2.4 節以降で説明するいくつかの
awk
機能についても触れます。
2.3.1 単純変数
単純 (スカラ) 変数は,必要に応じて値を割り当てることによって,任意の数だけ作成することができます。
明示的に値を割り当てる前に変数を参照した場合,awk
は,その変数を作成し,空文字列値 (""
) を代入します。
変数には,アクション式内での使用方法に応じて,数値 (浮動小数点) または文字列値を指定することができます。
たとえば,x = 1
という式では,x
は数値変数になります。
同様に,式
x = "smith"
では,x
は文字列変数になります。
しかし,awk
では,必要に応じて,文字列と数値は,互いに自由に変換されます。
その結果,たとえば
x = "3"+"4"
という式では,引数がリテラル文字列であるにもかかわらず,awk
は
x
に値 7 を代入します。
数値以外の値を含む変数を数値式で使用した場合には,awk
は,数値 0 を変数に代入します。
次に例を示します。
y = 0 z = "ABC" x = y+z print x, z
この例の場合,"0 0" が出力されます。 これは,y には値 0 が代入され,z に代入された値 ABC も数値 0 に変換されるためです。
たとえば,x = 2 ""
のように,変数値にヌル文字列 ( ""
) を連結することによって,変数を強制的に文字列として処理することができます。
文字列を連結する方法についての詳細は,2.12 節を参照してください。
変数値の先頭に 0 を追加すれば,変数を強制的に数値として処理することができます。
これらの方法は,変数のタイプを固定したい場合に便利です。
たとえば,x
の値が 0100 で
y
の値が 1 の場合,awk
は通常,両方の変数を数値として処理して,x
を
y
よりも大きいものと見なします。
両方の変数を強制的に文字列として処理すると,x
は
y
よりも小さくなります。
これは,ASCII コードで 0 が 1 よりも前にあるためです。
2.3.2 フィールド変数
現在のレコード内の各フィールドはフィールド変数とも呼ばれ,単純変数の特性を共有しています。
これらのフィールドは,算術または文字列演算に使用され,数字または文字列の値を代入することができます。
awk
では,現在のレコード ($0
) を明示的に変更することができます。
次のアクションは,第 1 フィールドをレコード番号に置き換えて,結果のレコードを出力します。
{ $1 = NR; print }
次の例は,第 2 および第 3 フィールドを加算して,結果を第 1 フィールドに保存します。
{ $1 = $2 + $3; print $0 }
$0
をプリントすることは,引数を付けないでプリントすることと同じです。
フィールド参照に数値式を使用することができます。 次の例は,第 1,第 2,および第 6 フィールドを出力します。
i = 1 n = 5 { print $i, $(i+1), $(i+n) }
2.3.1 項で説明されているように,awk
は,文字列と数値間の変換を行います。
フィールドの使用方法によって,awk
がそのフィールドを文字列または数値のいずれで処理するかが決まります。
指定されたフィールドの使用方法が決められていない場合には,awk
はフィールドを文字列として処理します。
awk
プログラムは,必要に応じて入力レコードを複数のフィールドに分割します。
2.3.3 配列変数
フィールド変数と同じように,配列変数も単純変数の特性を持っています。
配列変数は,算術演算または文字列演算で使用し,数字または文字列の値を代入することができます。
配列要素を宣言したり,初期化する必要はありません。awk
によって配列要素が作成され,最初に参照された時点で,配列要素は空文字列 (""
) に初期化されます。
delete
文を使って不要な配列要素を削除することができます。
詳細は,表 2-7
を参照してください。
添字は,大カッコで囲むことによって示します。 添字には,文字列の値を含む,ヌル以外の値を使用することができます。 数字の添字の例を次に示します。
x[NR] = $0
この式は,配列 x の NR 番目の要素を作成し,現在の入力レコードの内容をその要素に代入します。 次に,文字列の添字を使用する方法の例を示します。
/apple/ { x["apple"]++ } /orange/ { x["orange"]++ } END { print x["apple"], x["orange"] }
このプログラムは,apple
を含むそれぞれの入力レコードに対して,配列
x
の
apple
番目の要素をインクリメントします。orange
についても同じ処理を行います。
その結果,このプログラムは,これらのそれぞれの単語を含むレコードの合計を計算し,出力します (単語はレコード内に複数含まれることがあるため,これは単語の数ではありません)。
配列要素を配置するために
if
または
while
文を使用した場合,問題が発生する可能性があります。
制御構造については
2.10 節を参照してください。
配列の添字が存在しない場合は,これらの文でヌル値の配列要素を持った新しいハッシュ・テーブル・エントリとして添字が追加されてしまいます。
たとえば,次のような場合です。
if (exists[$2] == 1) print i
このような問題を避けるには,次のようなコードを使用してください。
このコードでは,配列要素が存在し,かつ配列要素の値が
1
の場合のみ
i
がプリントされます。
if (i in exists) { if (exists[i]== 1) print i }
配列の全要素を処理するには,次のような for ループを使用します。
for(i in exists) { print exists[i] }
また,while
と関係演算子を併用する場合にも,このようなコーディングを使用してください。
リテラル文字列や文字列変数の値は,split
関数を使用して分割し,配列に格納することができます。
たとえば次のようにします。
n = split("Thu Mar 18 11:19:40 EST 1999", array1) m = split(array1[4], array2, ":")
この例の 1 行目では,リテラル文字列を分割して配列
array1
の要素 (array1[1]
から
array1[n]
) に格納します。
このとき,n は文字列内のフィールドの数です。
2 行目では,コロン (":"
) をセパレータとして,変数
array1[4]
を分割し,array2
に格納します (2.9 節
を参照)。
2.3.4 組み込み awk 変数
awk
プログラムでは,表 2-2
に示す組み込み変数を使用できます。
表 2-2: awk の組み込み変数
変数名 | 説明 |
$0 |
現在のレコードの内容 |
$n |
入力レコードのフィールド
n
の内容 --
|
ARGC |
|
ARGV |
|
CONVFMT |
数値の変換フォーマット -- 省略時の設定は
|
ENVIRON |
|
FILENAME |
現在の入力ファイルの名前 -- 入力ファイル名が指定されていない場合は, |
FNR |
現在のファイル内の現在のレコードの番号 -- 複数のファイルを処理しているときに,現在のファイルが複数ファイルの最初のファイルではない場合は, |
FS |
フィールド・セパレータとして使用する文字または式 -- 省略時の設定は任意の数の空白です。 FS = ",[ \t]*|[ \t]+"
|
NF |
現在のレコードのフィールド数 |
NR |
最初に読み取られたファイルの先頭から順番に数えた場合の,現在のレコード番号 -- 複数のファイルを処理しているときに,現在のファイルが最初の読み取りファイルではない場合, |
OFMT |
数値の出力書式の指定 -- 省略時の設定は
|
OFS |
出力フィールド・セパレータ -- データ書き込み時にフィールド間に出力される文字または文字列です。 省略時の設定は空白です。 |
ORS |
出力レコード・セパレータ -- データ書き込み時にレコード間に出力される文字です。 省略時の設定は改行文字です。 |
RLENGTH |
|
RS |
入力レコード・セパレータとして使用する文字 |
RSTART |
|
SUBSEP |
配列要素内の複数の添字用のセパレータ -- 省略時の設定は,ASCII FS 文字 \034 です。 |
これらの変数の詳細については,
awk
(1)2.4 パターンとしての正規表現
最も単純な正規表現は,リテラル文字列です。awk
では,正規表現をスラッシュで囲まなければなりません。
正規表現の中にスラッシュを入れる場合には,バックスラッシュでスラッシュをエスケープします。
たとえば,/\/usr\/share/
は,文字列
/usr/share
と一致する正規表現です。
次に示すのは,文字列
the
を含むすべてのレコードを出力する
awk
プログラムの例です。
/the/
この正規表現には空白または他の修飾子が指定されていないため,プログラムは,単語として "the" を含むレコードと,northern のように単語の一部分として文字列 "the" を含むレコードの両方を表示します。
正規表現は,大文字と小文字を区別します。 "The" または "the" のいずれかを検出するには,次のように正規表現をカッコで囲ってください。
/[Tt]he/
awk
プログラムは,第 1 章
で説明した拡張正規表現をサポートします。
また,^
記号および
$
記号も,行全体とともに,特定のフィールドまたは変数に適用できます。
次の例は,文字列 cat または cats のフィールドを照合しますが,これらの文字列を含む単語 (たとえば concatenate など) は照合しません。
{ for (i=1;i<=NF;i++) if ($i ~ /^cats?$/) print }
関係式を使用すると,レコードの特定のフィールドだけを照合したり,あるいは,数字または文字列に関連した他の照合を行うことができます。2.3 節では,パターンに関係式を使用する例を示しました。awk
プログラムでは,パターンの作成に使用できるように,次の関係演算子を定義しています。
== |
等しい |
!= |
等しくない |
< |
より小さい |
> |
より大きい |
<= |
より小さいか等しい |
>= |
より大きいか等しい |
~ |
正規表現と照合する |
!~ |
正規表現と照合しない |
リテラル文字列と数値を照合する場合には,==
(等しい) および
!=
(等しくない) 演算子を使用します。
次に例を示します。
str == "literal string" num != 23 $NF == 1991
この例の最後の行は,$
n
構文に組み込み変数
NF
を組み合わせて,レコードの最後のフィールドの値と照合しています。
正規表現と照合させるには,次のように
~
(正規表現と照合する) および
!~
(正規表現と照合しない) 演算子を使用します。
str ~ /[Ll]iteral/
組み立て式に対しても,関係式をテストすることができます。
たとえば,次のパターンは,第 2 フィールド ($2
) が第 1 フィールド ($1
) よりも 100 以上大きいレコードを検出します。
$2 > $1 + 100
次のパターンは,偶数個のフィールドからなるレコードを検出します。
NF % 2 == 0
式には,2.8 節に示されている演算子を使用します。
絶対比較演算子を使用して,文字列と照合させることができます。 たとえば,次のパターンは,"s" で始まるレコードまたは文字セットの中で s の後にある任意の 1 文字 (t,u,v,w,x,y,z) を検出します。
$0 >= "s"
次のブール演算子を使用すれば,2 つ以上のパターンを結合することができます。
&& |
論理積 (AND) |
|| |
論理和 (OR) |
! |
否定 (NOT) |
たとえば,前述した例で英数字以外の記号と照合しないようにするためには,次のように 2 つの式を組み合わせることもできます。
($0 >= "s" && $0 < "{")
左中カッコは,ASCII コードの英字 z の次の文字です。
2.6 パターン・レンジの使用
操作するレコードのグループを選択する場合には,パターン・レンジを使用します。
パターン・レンジは,コンマによって区切られた 2 つのパターンから構成されています。
最初のパターンは,レンジの開始を指定し,2 番目のパターンはレンジの終了を指定します。awk
プログラムは,2 つのパターンと照合するレコードも含め,レンジ内のすべてのレコードに対して対応するアクションを実行します。
たとえば,次のとおりです。
NR==100,NR==200 { print }
このプログラムは,レコード 100 で始まり,レコード 200 で終わる 101 個のレコードを入力ファイルからプリントします。
パターン・レンジを使用した場合に,他のパターンが,レンジ内のレコードと照合しなくなることはありません。 ただし,入力ファイルは 1 レコードずつ処理され,次のレコードが処理される前に,それぞれのレコードに対する適切なすべてのアクションが行われるため,次の例で示すように,順序どおりにアクションが行われていないようにみえることもあります。
2,4 { print } /share/ { print "Found share" }
このプログラムを次の入力ファイルに適用します。
This is a test file Line two Try to share things Line four Last line of file
このファイルが
awk
によって処理されると,出力は次のようになります。
Line two Try to share things Found share Line four
レコード 4 が最初のパターンに照合するかどうかを検証される前に,2 番目のアクションがレコード 3 に適用されます。
2.7 awk のアクション
アクションには,たとえば
print
のように単一のコマンドを指定することも,複数のコマンドを指定することもできます。
アクションとして,レコードまたはレコードの一部の選択を指定することもできます。
アクション内の関係式を代わりに使用して,明示的にパターンを指定しないプログラムを作成することもできます。
このようなプログラムは,次の例に示すように,C プログラムに非常に似ています。
{ if ($1 == 0) { print; printf("%5.2f\n", $2+$3) } else { printf("%5.2f\n", $1+$2) } }
注意
awk
には必須ではありません。 しかし,このセミコロンがあっても,エラーの原因となることはありません。
アクション文内の式を作成する場合には,表 2-3
に示されている演算子を使用します。
表 2-3: awk アクションの演算子
優先順位 | 演算子 | 説明 | 例 |
1 | () |
カッコ | 3+x*4 = 3+(x*4) |
2 | $ |
フィールド参照 | $(NF-1) = 最後のフィールドの次 |
3 | ++ |
インクリメント | この表の後の説明を参照 |
3 | -- |
デクリメント | この表の後の説明を参照 |
4 | ^ |
べき乗 | 2^3 = 8 |
5 | ! |
論理否定 | !x は x と等しくない |
6 | + |
単項演算子のプラス | +4 = 4 |
6 | - |
単項演算子のマイナス | -4 は負の 4 |
7 | * |
乗算 | 2*4 = 8 |
7 | / |
除算 | 6/3 = 2 |
7 | % |
モジュロ (剰余) | 7%3 = 1 |
8 | + |
加算 | 2+3 = 5 |
8 | - |
減算 | 7-3 = 4 |
9 | 空白 |
連結 | "a" "b" = "ab" |
10 | < |
より小さい | 5 < 6 |
10 | > |
より大きい | "qrs" > "abc" |
10 | <= |
より小さいか等しい | 3 <= 3 |
10 | >= |
より大きいか等しい | 4 >= 2 |
10 | == |
等しい | 9 == 9 |
10 | != |
等しくない | "xyz" != "abc" |
11 | ~ |
正規表現と一致 | "tmp.c" ~ /[a-z]+\.[ch]/ |
11 | !~ |
正規表現と一致しない | "tmp.o" !~ /[a-z]+\.[ch]/ |
12 | in |
配列のメンバシップ | for (j in arr) print arr[j] |
13 | && |
論理積 (AND) | X |
14 | || |
論理和 (OR) | X |
15 | ?: |
条件式 | x == -1 ? "error" : "OK" |
16 | = |
代入 | x = 3 |
16 | ^= |
値をべき乗 | x^=3 は x = x^3 と同等 |
16 | *= |
値を乗算 | x*=y は x = x*y と同等 |
16 | /= |
値を除算 | x/=y は x = x/y と同等 |
16 | %= |
値のモジュロ | x%=y は x = x%y と同等 |
16 | += |
値をインクリメント | x+=y は x = x+y と同等 |
16 | -= |
値をデクリメント | x-=y は x = x-y と同等 |
入力ファイルのすべての第 1 フィールドの合計,およびすべての第 2 フィールドの合計をプリントする例を次に示します。
{ s1 += $1; s2 += $2 } END { print s1,s2 }
インクリメントおよびデクリメント演算子の位置は,解釈に大きな影響を与えます。i++
という式は,i
の現在の内容を評価してから,i
をインクリメントします。++i
という式を使用すると,awk
は評価の前に
i
をインクリメントします。
次に例を示します。
$ echo "3 3" | awk '{ > print "$1 =", $1 "; $1++ =", $1++ "; new $1 =", $1 > print "$2 =", $2 "; ++$2 =", ++$2 "; new $2 =", $2 > }' $1 = 3; $1++ = 3; new $1 = 4 $2 = 3; ++$2 = 4; new $2 = 4
awk
は,表 2-4
に示す組み込み算術関数をサポートしています。
表 2-4: 組み込み awk 算術関数
関数 | 説明 |
atan2(x |
x/ y
で指定された値の逆正接を返します。 |
cos( expr) |
expr で指定された値 (ラジアン) の余弦を返します。 |
exp( arg) |
arg
の自然真数 (底はe) を返します。
たとえば,exp(0.693147)
は値 2 を返します。log( arg)
を参照。 |
int( arg) |
arg の整数部を返します。 |
log( arg) |
arg
の自然対数 (底はe) を返します。
たとえば,log(2)
は 0.693147 を返します。exp( arg)
を参照。 |
rand |
偽似乱数 (0 <= n < 1) を返します。 |
sin( arg) |
arg で指定された値 (ラジアン) の正弦を返します。 |
sqrt( arg) |
arg の平方根を返します。 |
srand( seed) |
rand
に引き続くコールに対する偽似乱数のシードとして
seed
を使用します。
シードが何も指定されない場合には,日付の時間が使用されます。
返す値は,その前のシードです。 |
awk
は,表 2-5
に示す組み込み文字列関数をサポートしています。
関数 | 説明 |
gsub(expr,s1,s2) |
文字列
s2
内で正規表現
expr
に一致するすべての文字列を,s1
で指定された文字列に置換します。s2
が指定されていない場合には,現在の入力レコードが使用されます。
正規表現
expr
は照合のたびに再評価されます。
この関数は置換した数を表わす値を返します。sub(expr,s1,s2)
を参照。 |
index(s1,s2) |
文字列 s2 中の部分文字列 s1 の文字位置を返します。s2 が s1 に含まれない場合,この関数は 0 を返します。 |
length |
現在のレコードの文字列の文字数を返します。 |
length(arg) |
arg
で指定された文字列の長さを返します。length
を参照。 |
match(s,expr) |
文字列
s
内で正規表現
expr
との一致が見つかった文字位置を返します。RSTART
変数を照合が始まる文字の位置に設定し,RLENGTH
変数を照合文字列の長さを表す値に設定します。
一致するものがない場合,この関数はゼロ (0) に返します。 |
split(s,array,sep) |
文字列
s
を
array[1]...[n]
の連続する要素に分割し,要素の数を返します。
オプションの
sep
引数には,現在使用されているフィールド・セパレータ (省略時は
FS
変数の内容) 以外のフィールド・セパレータを指定することができます。 |
sprintf(f,e1,e2
,...) |
引数
e1
等を含む文字列を
printf
コマンドと同じ方法でフォーマットして返します。
プリントは行いません。 |
sub(expr,s1,s2) |
文字列
s2
内で正規表現
expr
に一致する最初の文字列を,s1
で指定される文字列と置換します。
s2
が指定されていない場合は,現在の入力レコードが使用されます。
この関数は置換した数 (0 か 1) を返します。gsub(expr,s1,s2)
を参照。 |
substr(s,m,n) |
文字位置 m から始まり,長さが n 文字の,文字列 s の部分文字列を返します。 s の最初の文字の文字位置は 1 です。n が省略された場合,あるいは文字列の長さが n 文字末満の場合は,残りの文字列が返されます。 |
tolower(s) |
文字列 s 内の大文字をすべて小文字に変換する。 引数がない場合には,現在のレコードを処理します。 |
toupper(s) |
文字列 s 内の小文字をすべて大文字に変換する。 引数がない場合は,現在のレコードを処理します。 |
awk
は,表 2-6
に示すその他の組み込み awk 関数をサポートしています。
関数 | 説明 |
close( arg) |
arg
で指定したファイルまたはパイプをクローズします。 |
system(" command") |
システム・コマンドを実行し,終了 (Exit) 状態を返します。
変数名として
awk
が解釈しないように,コマンド全体を " 記号で囲みます。 |
awk
プログラムでは,次の構文で関数を作成することもできます。
function
name(
parameter-list) {
statements}
function
の代わりに
func
を使用することもできます。
新たに作成した関数の場合,関数を定義する場合も関数を作成する場合も,関数名の後ろの左カッコと関数名との間にはスペースを入れないで記述する必要があります。
関数宣言のパラメータのリストで使用した名前は,その関数内で使用する形式的なものです。
実際に関数を呼び出す際に,これらの形式的なパラメータは呼び出し文で指定された値に
awk
によって置き換えられます。
関数は再帰的に使用できます。
関数エントリ上で形式的なパラメータを特別に宣言することによって,関数に対してローカル変数を定義することができます。 すべてのローカル変数は空の文字列あるいは 0 に初期化されます。 実パラメータとローカル変数とを混同しないように,次の例のように余分なスペースを使用してローカル変数を区別することができます。
function foo(in, out, local1, local2) { local1 = "foo" local2 = "bar"
.
.
.
}
awk
言語は,表 2-7
に示す制御構造をサポートしています。
特に明記しない限り,これらの制御構造は C 言語の場合と同じように動作します。
単一の制御構造のアクションとしていくつかの文を実行する場合は,それらの文を中カッコで囲みます。
制御構造内で実行する文が 1 つだけの場合は,中カッコは省略できます。
次の例の最初の 2 つの
if
制御構造には,実行する文がそれぞれ 1 つ含まれています。
これらの制御構造の機能は,どちらも同じです。
{ if (x == y) print if (x == y) { print } if (x == y) { print $3 printf("Sum = %d\n", x+z) } }
制御構造 | 説明 |
if-else |
次のように,"else" と "if" を記述する順番は重要です。
if ( $1 == "abc" ) { print("found abc\n"); } else if ( $1 == "qrs" ) { print("found qrs\n"); } else if ( $1 == "xyz" ) { print("found xyz\n"); } else { print("did not find "abc", "qrs", or "xyz"\n"); }
|
delete |
delete 文を使用すると,配列要素を削除することができます。 たとえば次の例では,配列 x の要素がすべて削除されます。
{ for(j in x) delete x[j] }
|
while |
テストされた条件が真でなくなるまでの間, { i = 1 while(i<=NF) print $i++ }
|
for |
{ expr1
たとえば,上記の
{ for(i=1;i<=NF;++i) print $i }
$2=="="{name_value_pairs[$1]=$3} end{ for (i in name_value_pairs) print name_value_pairs[i] }
|
break |
break
文を実行すると,while
ループまたは
for
ループから即座に抜けます。 |
コメント |
{ print x,y # This is a comment }
|
continue |
continue
文は,ループを最初から繰り返します。 |
getline |
getline
文を実行すると,awk
は,現在の入力レコードを捨て,次の入力レコードを読み取り,現在の位置からパターンの走査を開始します。
getline
var
を使用すると,getline
の入力を変数に割り当てることができます。var
を指定しなければ,入力は現在のレコードに割り当てられます。 |
next |
next
文を実行すると,awk
は,現在の入力レコードを捨て,次の入力レコードを読み取り,プログラム・ファイルの先頭からパターンの走査を開始します。 |
exit |
exit
文は,入力ファイルの終端に到達したときのようにプログラムを停止します。 |
awk
プログラムは,入力ファイルの開始および終了を定義するための 2 つの特別なパターン・キーワード
BEGIN
および
END
を識別します。
BEGIN
は,最初のレコードを読み取る前に,入力の先頭と一致します。
このため
awk
は,入力ファイルを処理する前に,このパターン (BEGIN
) に対応するアクションを 1 回実行することになります。
たとえば,ファイル内のすべてのレコードのフィールド・セパレータをコロン ( :
) に変更する場合は,プログラム・ファイルの最初に次の 1 行を記述します。
BEGIN { FS = ":" }
この例のアクションは,コマンド行で
-F:
フラグを使用した場合と同じです。
同様に,END
は,最後のレコードを読み取った後に,入力ファイルの最後と一致します。
このため,awk
は,入力ファイルを処理した後,このパターン (END
) に対応するアクションを 1 回実行することになります。
たとえば,入力ファイルのレコードの総数を出力するためにはプログラム・ファイルに次のように記述します。
END { print NR }
変数名を 1 つの式にまとめることによって,文字列を連結します。
たとえば,コマンド
print $1 $2
は,現在のレコードの最初の 2 つのフィールドを構成する文字列を,空白を入れないでプリントします。
文字列を連結する場合は,変数,数値演算子,関数を使用することができます。
変数と数値演算子についての詳細は,2.3.1 項および
2.8 節を参照してください。
関数
length($1 $2 $3)
は,最初の 3 つのフィールドの長さを文字数で返します。awk
関数のリストについては,2.9 節を参照してください。
連結する文字列がフィールド変数 (2.3.2 項参照) である場合は,空白で名前を区切る必要はありません。
たとえば,式
$1$2
は,$1 $2
と同一です。
2.13 リダイレクションとパイプ
特に指定しない限り,print
文および
printf
文は,出力を標準出力ファイルに書き込みます。
標準リダイレクション演算子を使用すれば,プリント文の出力をリダイレクトすることができます。
次に例を示します。
print $0, $3, amt >> "reportfile"
この例は,その出力を標準出力に書き込まないで,reportfile
という名前のファイルに追加します。
リダイレクションの最初のインスタンスの前に
reportfile
がない場合は,reportfile
が作成されます。
この例の出力ファイル名は引用符で囲まれています。
引用符は,ファイル名を変数名と区別するために必要です。
書き込みは,指定されたファイル,標準出力のいずれにも行うことができます。
print
と
printf
文は常に,その出力を標準出力に送ります。
次の例では,出力を標準エラー出力に送ります。
print "oops: did not find expected input" | " cat 1>&2"
また,プリントされる出力を他のコマンドにパイプすることもできます。
次に,awk
の出力を
tr
コマンドにパイプして,大文字をすべて小文字に変換する例を示します。
print | "tr '[A-Z]' '[a-z]'"
リダイレクションを使用する場合と同様に,出力のパイプ先のコマンドは,引用符で囲まなければなりません。
awk
は,標準リダイレクト演算子を使用して
getline
ヘの入力をリダイレクルトすることができます。
そのため,次のように
getline
文への入力をパイプで提供することができます。
expr | getline
この場合,expr はシステム・コマンドとして解釈されます。
次の例では,システム・コマンドからの出力を読み取ります。
BEGIN { cmd = "ps aux" while( cmd | getline > 0 ) { if ( $2 == "PID" ) continue unique_users[$1]++ } close(cmd) for(i in unique_users) { printf("%3d %s\n", unique_users[i], i) } }
出力用にオープンできるファイルの数は制限されています。awk
プログラムには,ユーザのオープン・ファイル記述子の省略時の制限が適用されます。
しかし,効率を高めるために,close(
arg)
文を使用して,出力用にオープンしたファイルのうち不要なものをクローズすることもできます。
たとえば,次のようにします。
{ if ( cur_file != "/tmp/" $1 ) { close(cur_file) cur_file = "/tmp/" $1 } print $2 >cur_file } END { close(cur_file) }