LoginSignup
126
159

More than 5 years have passed since last update.

AWKのこういう時はどう書く?

Last updated at Posted at 2016-03-01

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
126
159
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
126
159