awk のシステム変数のチートシートと使い方のメモ。
はじめに
awk のシステム変数はよく使うものとたまに使うものがあるけど、たまに使うものは結構忘れてしまって使うときになって調べるのが面倒くさいのでチートシートを作って、あと使い方の例をメモしてみた。
環境は Mac なのでそのへんのバージョンをメモしておく。
macOS のバージョン。
$ sw_vers | grep Product ProductName: macOS ProductVersion: 11.4
awk のバージョン。
$ awk --version awk version 20200816
awk のシステム変数
awk のシステム変数は2つのタイプがあって、1つはフィールドセパレータとかレコードセパレータみたいにデフォルト値を変更できる変数で、もう1つはカレントレコードのフィールド数とかカレントレコードの番号みたいに処理で利用できる変数がある。 2つのタイプの変数をそれぞれチートシートと使い方の例をメモしておく。
デフォルト値を変更できる変数
チートシート
デフォルト値を変更できる変数のチートシートをメモしておく。
| 変数名 | 意味 | デフォルト値 |
|---|---|---|
| FS | フィールドセパレータ。 awk は入力をこの値でフィールドに分割する。 |
スペース |
| OFS | 出力時のフィールドセパレータ。 awk はフィールドをこの値で分割して出力する。 |
スペース |
| RS | レコードセパレータ。 awk は入力をこの値でレコードに分割する。 |
改行 |
| ORS | 出力時のレコードセパレータ。 awk はレコードをこの値で分割して出力する。 |
改行 |
FS
FS 変数はフィールドを分割する値を指定する。
FS 変数はデフォルトはスペースなのでレコードはスペースでフィールドに分割するけど、* (アスタリスク) でレコードを分割するならこんな感じ。
$ echo 'a*b*c' | awk 'BEGIN{FS="*"}{print $1, $2, $3}'
a b c
OFS
OFS 変数は出力時のフィールドセパレータを指定する。
OFS 変数はデフォルトはスペースなのでフィールドはスペースで区切って出力するけど、_ (アンダースコア) でフィールドを区切って出力するならこんな感じ。
$ echo 'a*b*c' | awk 'BEGIN{FS="*";OFS="_"}{print $1, $2, $3}'
a_b_c
OFS 変数は \n (改行) を指定すると改行でフィールドを区切って出力することもできる。
$ echo 'a*b*c' | awk 'BEGIN{FS="*";OFS="\n"}{print $1, $2, $3}'
a
b
c
RS
RS 変数はレコードを分割する値を指定する。
RS 変数はデフォルトは \n (改行) なので入力は改行でレコードに分割するけど、入力レコードがブロック状になってて空行で区切られてるレコードを分割するならこんな感じ。
$ cat rs.txt
Japan
日本
81
USA
アメリカ合衆国
1
$ awk 'BEGIN{RS=""}{print $1, $2, $3}' rs.txt
Japan 日本 81
USA アメリカ合衆国 1
ORS
ORS 変数は出力時のレコードセパレータを指定する。
ORS 変数はデフォルトは \n (改行) なのでレコードは改行で区切って出力するけど、---- でレコードを区切って出力するならこんな感じ。
$ awk 'BEGIN{RS="";ORS="\n----\n"}{print $1, $2, $3}' rs.txt
Japan 日本 81
----
USA アメリカ合衆国 1
----
処理で利用できる変数
チートシート
処理で利用できる変数のチートシートをメモしておく。
| 変数名 | 意味 |
|---|---|
| NF | カレントレコードのフィールド数 |
| NR | カレントレコードの番号 |
| FNR | 入力ファイルごとのカレントレコード番号 |
| FILENAME | カレント入力ファイルの名前。 入力がパイプのときは空になる。 |
NF
NF 変数はレコードが所定のフィールドがあるかをチェックするのに使える。
たとえばレコードが3つ以上のフィールドをもつときだけ出力するならこんな感じ。
$ cat nf.txt
a b c
a b
a b c d
a
$ awk 'NF>=3{print}' nf.txt
a b c
a b c d
NR
NR 変数は任意の番号のレコードだけ処理したりレコード番号を出力するのに使える。
たとえばファイルの内容にレコード番号を付与して出力するならこんな感じ。
$ awk '{print NR ":" $0}' nf.txt
1:a b c
2:a b
3:a b c d
4:a
FNR
NR 変数は awk に入力するすべてのレコードの通し番号になるけど、 FNR 変数は入力ファイルごとのレコード番号を出力するのに使える。
複数ファイルの内容にファイルごとのレコード番号を付与して出力するならこんな感じ。
$ cat a.txt
a
aa
aaa
$ cat b.txt
b
bb
bbb
$ cat c.txt
c
cc
ccc
# FNR 変数はファイルごとのレコード番号が入る
$ awk '{print FNR ":" $0}' a.txt b.txt c.txt
1:a
2:aa
3:aaa
1:b
2:bb
3:bbb
1:c
2:cc
3:ccc
# NR 変数はすべてのレコードでの通しのレコード番号が入る
$ awk '{print NR ":" $0}' a.txt b.txt c.txt
1:a
2:aa
3:aaa
4:b
5:bb
6:bbb
7:c
8:cc
9:ccc
FILENAME
FILENAME 変数は入力ファイルの名前を出力したりチェックするのに使える。
たとえばさきほどの FNR 変数の例だけどファイル名も出力するならこんな感じ。
$ awk '{print FILENAME ":" FNR ":" $0}' a.txt b.txt c.txt
a.txt:1:a
a.txt:2:aa
a.txt:3:aaa
b.txt:1:b
b.txt:2:bb
b.txt:3:bbb
c.txt:1:c
c.txt:2:cc
c.txt:3:ccc