linuxのコマンドラインでデータ加工をする際によく使うAWKですが、個人的につまずいた使い方について、
覚え書きとして残します。誰かの助けになれば…
- 組み込み関数覚え書き
FS 入力フィールドセパレータ(空白とタブ)
CNVFMT 数値を文字列に変換するフォーマット
OFMT 数字の出力フォーマット(%.6g)
OFS 出力フィールドセパレータ(空白)
ORS 出力レコードセパレータ(\n)
RS 入力レコードセパレータ(\n)
SUBSEP 配列添字セパレータ(\034)
ARGC コマンド行の引数の数+1
ARGV コマンド行の引数の配列
ENVIRON["..."] 環境変数の値
FILENAME 入力ファイル名
FNR 入力ファイルの通算レコード
NF 入力レコードのフィールド数
NR 入力レコード総数
RLENGTH matchで適合した文字列の長さ
RSTART matchで適合した文字列の開始位置
- セパレータを指定して処理したい
# -Fでセパレータを指定
awk -F ":" '{ print $1 " " $3 }' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
uucp 10
operator 11
- 各フィールドをループしたい
awk '{for (i = 1; i <= NF; i++) print $i;}' data.txt
- 複数の記号をセパレータとして使用したい
#正規表現を使用するとできる
#以下はスペースと:と/を区切り文字として使用した場合の例
echo "2016/03/01 12:12:12" | awk -F'[ :/]' '{print $2}'
- 特定の正規表現のパターンにマッチする行だけ処理する
awk -F':' '$0 ~ /root/{ print}' /etc/passwd
- 文字列を数値に変換する
#特に何もする必要がない。数値を表した文字列は数値に自動的に変換される。
echo | awk '{ x="1.01"; x=x+1; print x}'
2.01
- 部分文字列を作成する
echo 'abcde' | awk '{print substr($0, 2)}'
- 特定の制御文字でフィールドを区切る
#下の例では^Aの部分が制御文字
#^Aの場合はCtrl+v Ctrl+Aでターミナル上から入力できる
more control_code.txt
a^Ab
awk -F'^A' '{print $1 ":" $2}' control_code.txt
a:b
#バイナリの値を以下のように指定する事もできる
awk -F'\01' '{print $1 ":" $2}' control_code.txt
a:b
- csvのカラム数が8個の行だけ抽出
8get.awk
BEGIN {
while (getline < "/work/test.csv" > 0) {
col = split($0,field,",")
if ( col == 8 ) print $0
}
close("/work/test.out.csv");
}
実行
gawk -f /work/8get.awk
- ゼロパディング(ゼロ埋め)
echo "1" | awk '{printf "%02d", $1}'
> 01
- フォーマット変換
# xを○○に変換
printf("%d\n",x) #整数として出力
printf("%5d\n",x) #5桁で右詰の整数として出力
printf("%e\n",x) #浮動小数点数(eの後の数字は10の累乗を表す)
printf("%7.2f\n",x) #浮動小数点数、7桁で小数第2位まで
printf("%6.2f\n",x) #浮動小数点数、6桁で小数第2位まで
printf("%5.2f\n",x) #浮動小数点数、5桁で小数第2位まで
printf("%4.2f\n",x) #浮動小数点数、4桁で小数第2位まで
printf("%o\n",x) #8進数として出力
printf("%x\n",x) #16進数として出力
printf("%c\n",x) #文字コードして対応するアルファベットを出力
printf("%s\n",x) #そのまま文字列として出力
printf("%10s\n",x) #右詰で10桁のスペースに出力
printf("%-10s\n",x) #左詰で10桁のスペースに出力
printf("%.3s\n",x) #左詰で3文字のみ出力
printf("%10.3s\n",x) #右詰で10桁のスペースに3文字を出力
printf("%-10.3s\n",x) #左詰で10桁のスペースに3文字を出力
#ワンライナーで使う場合は以下のように置き換えればOK
echo 12345 | awk '{ printf("%-10.3s\n",$0) }'
#ちょっと穿った使い方
- ファイルを結合してみる(inner join風)
使うワンライナーはこんな感じ
awk 'F==0{a[$1]=$2;next}{print $1 "\t" a[$1] "\t" $2}' data1.tsv F=1 data2.tsv
data1.tsv と data2.tsvの1カラム目を比較して、おなじだったら、カラムを右に結合
例として、以下のような2つのtsvがあったとして、上記のコマンドを打つと、結果が以下のように出る
joinのほうが絶対簡単だと思うけれど、awkでやってみたいと思ったので、やってみた。
data1.tsv
a 100
b 200
c 250
d 500
data2.tsv
a red
d black
b blue
c green
b blue
d black
結果
a 100 red
d 500 black
b 200 blue
c 250 green
b 200 blue
d 500 black