箱のプログラミング日記。

えんじにあ奮闘記

awkコマンドを使ってみた

f:id:y_hakoiri:20191102121618j:plain

業務でCSVをごにょごにょする必要があったのでawkコマンドを学習してみた。

awkコマンドとは

AWKはパターンとアクションを組み合わせるプログラミング言語です。

引用元:「シェル芸」に効く!AWK処方箋

「パターンにマッチした場合はアクションを実行する」という処理ができる。

使い方として最もメジャーなのは、テキストの中からパターンに一致する箇所のみ抽出したり、CSVファイルの中から特定の列だけ抜き出したり、、みたいなことだろうか。

使ってみる

$ echo a b c | awk '{print}'
a b c

この場合、printが「アクション」にあたる。パターンは省略されている

$ echo a b c | awk '{print $0}'
a b c

出力結果は一緒だが、パターンを省略しない場合はこのようになる。

「$0」というのは渡された文字列全体を表す。「a b c」をスペースで区切ったものを先頭から$1, $2, $3...と参照することができ、$0は文字列全体を参照できる。

Rubyなどの配列のインデックスのように、先頭が0から始まるわけではないので注意。

$ echo a b c | awk '{print $1}'
a
$ echo a b c | awk '{print $1, $2}'
a b

ここでprint $1, $2としているにもかかわらず「a, b」ではなく「a b」と出力されているのは、出力時の区切り文字がデフォルトで空白になっているから。

出力時の区切り文字を指定

組込変数OFSに代入する。

$ echo a b c | awk -v OFS="," '{print $1, $2}'
a,b
$ echo a b c | awk -v OFS="***" '{print $1, $2}'
a***b

入力時の区切り文字を指定

デフォルトでは空白が区切り文字として判断されるので

$ echo a,b,c | awk '{print $1, $2}'
a,b,c

これだとうまく行かない。

渡されたテキストをカンマ区切りで分割したい場合は-Fオプションで指定する

$ echo a,b,c | awk -F , '{print $1, $2}'
a b

組込変数OFSと組み合わせて、入力時も出力時もカンマで統一する場合

$ echo a,b,c | awk -F , -v OFS="," '{print $1, $2}'
a,b

こうなる。若干複雑になってきた

テキストファイルに対しての処理

テキストファイルを対象にすることもできる。

$ cat users.csv
id,name,age
1,hoge,24
2,fuga,34

このようなCSVがあったときに

$ cat users.csv | awk -F , -v OFS="," '{print $1, $2}'
id,name
1,hoge
2,fuga

こんなこともできる。

$ awk -F , -v OFS="," '{print $1, $2}' users.csv
id,name
1,hoge
2,fuga

パイプでつなげず対象ファイルを後ろに持ってきてもOK。

if文による条件マッチ

awkコマンドの中でも色々と関数があり、if文とかも使えるので

$ cat users.csv | awk '{if(NR!=1) print $0}'
1,hoge,24
2,fuga,34

こんなこともできる。

NRというのはawkの組込変数で、現在処理中の行数が格納されている。

if(NR!=1) print $0は「一行目じゃなかったら列全体をprintせよ」なので、結果的にCSVファイル最上の列名以外を全抽出することができる。

参考

「シェル芸」に効く!AWK処方箋