Linux環境でawkにより条件に合う行のみを抽出する

以下のようなスペース区切りのファイル「test.txt」から、2列目の値が5以下の行を抽出することを考えます。

a 1 100
b 2 200
c 3 300
d 4 400
e 5 500
f 6 600
g 7 700
h 8 800
i 9 900
j 10 1000

このような問題に対しては、linux環境でawk(オーク)を利用すると手軽に実現できます。Bash等で下記のようなシェルスクリプト「awk.sh」を作成します。もちろん、他のSHELLを用いても構いません。入力するテキストファイルを「file」パラメータに、閾値を「param」パラメータに与えています。閾値paramのawk文への与え方がポイントになります。

#!/usr/bin/env bash
#
file=$1
param=$2
#
cat ${file} | awk '{if ($2 <= threshold) print}' threshold=${param}

プログラムawk.sh中のfileにtest.txtを、paramに5を指定して実行します。

$ ./awk.sh test.txt 5
a 1 100
b 2 200
c 3 300
d 4 400
e 5 500

2列目の値が5以下の行のみを抽出することができました。なお、awk文中の「$2」は、test.txtの2列目を意味します(paramの$2とは関係ありません)。

タブ区切りのファイル「test.tsv」に対してはどうでしょうか。

a       1       100
b       2       200
c       3       300
d       4       400
e       5       500
f       6       600
g       7       700
h       8       800
i       9       900
j       10      1000

awkではスペース区切りとタブ区切りのファイルを同様に扱うことができます。

$ ./awk.sh test.tsv 5
a       1       100
b       2       200
c       3       300
d       4       400
e       5       500

では、コンマ区切りのファイルに対してはどうでしょうか。

a,1,100
b,2,200
c,3,300
d,4,400
e,5,500
f,6,600
g,7,700
h,8,800
i,9,900
j,10,1000

この場合、スペース区切りやタブ区切りのファイルに使ったawk.shではうまく行きません。いくつかの対応方法がありますが、手っ取り早いのは「-F」オプションに「,」を指定することです。CSVファイル用awkである「awk_csv.sh」は以下になります。

#!/usr/bin/env bash
#
file=$1
param=$2
#
cat ${file} | awk -F, '{if ($2 <= threshold) print}' threshold=${param}

上記のawk_csv.shによりカンマ区切りのファイルtest.csvの処理が可能になりました。

$ ./awk_csv.sh test.csv 5
a,1,100
b,2,200
c,3,300
d,4,400
e,5,500

もし1列目と3列目のみを出力し、2列目を出力したくない場合には、以下のような「awk_csv_13.sh」を作成します。

#!/usr/bin/env bash
#
file=$1
param=$2
#
cat ${file} | awk -F, '{if ($2 <= threshold) print $1,$3}' threshold=${param}

上記のawk_csv_13.shを用いると以下のような結果になります。

$ ./awk.sh test.csv 5
a 100
b 200
c 300
d 400
e 500

結果はスペース区切りで出力されます。もしカンマ区切りで出力したい場合は、「-v」オプションを使ってOFSにカンマを与える方法が良さそうです。これを「awk_csv_13_ofs.sh」とします(ソースコードは改行しません)。

#!/usr/bin/env bash
#
file=$1
param=$2
#
cat ${file} | awk -F, -v 'OFS=,' '{if ($2 <= threshold) print $1,$3}' threshold=${param}

上記のawk_csv_13_ofs.shを使って実行してみます。

$ ./awk.sh test.csv 5
a,100
b,200
c,300
d,400
e,500

うまく行ったようです。今回説明したやり方を応用することで、結構色々な処理ができるようになりますよ。