コピペコードで快適生活

明日使えるソースを自分のために

awk力をあげたくて勉強した時のノート

awk力を上げたくて下記サイトで勉強させていただいたときのノート
http://www.ie.u-ryukyu.ac.jp/~e085739/awk.tuts.html

基本

awkスクリプトの構造

BEGIN{アクション}
パターン 1 {アクション}
パターン 2 {アクション}
...
END{アクション}

awk の本処理, パターン{アクション}は
1. 入力テキストを 1 レコード (一行) ずつ読み込む
2. レコードをフィールドに区切る
3. レコードがパターンに合致していれば処理を行う # ここを書いていく
4. 入力テキストが終わるまで, 1 から 3 を繰り返す

# 最後のフィールドを出力(NFは特殊変数)
awk '{print $NF}'

# フィールド数を出力
awk '{print NF}' input.txt

# 読み込んでいるファイル名を出力
awk '{print FILENAME}' input.txt

# スクリプトを外部ファイルにする(./card.awk addr.txt のように実行)
# フィールドを,で区切るようにする
>||
#!/usr/local/bin/gawk -f
BEGIN{
    FS = ", "
}
{
    print "郵便番号: " $4
    print "住所: " $6
    print "名前: " $2 " " $3
}

変数

BEGIN{
    x = 2
    y = 3
    z = x + y
    str = "wtopia" # 文字列はダブルクォーテーションで囲む
    print x "+" y "=" z
    print  str
}

出力

BEGIN {
  print "abc"  # 標準出力
  print "abc" > "/tmp/abc.txt"  # ファイル出力
  printf "abc" # printfは改行されない
  pritnf "abc\n" # こうすれば改行される
}

printfで出力の細かな制御

BEGIN{
    x = 97.5
    printf ":%d\n", x
    printf ":%5d\n", x
    printf ":%e\n", x
    printf ":%7.2f\n", x
    printf ":%6.2f\n", x
    printf ":%5.2f\n", x
    printf ":%4.2f\n", x
    print "------------------"

    x = 100
    printf ":%o\n", x
    printf ":%x\n", x
    printf ":%c\n", x
    print "------------------"

    x = "January"
    printf ":%s\n", x
    printf ":%10s\n", x
    printf ":%-10s\n", x
    printf ":%.3f\n", x
    printf ":%10.3s\n", x
    printf ":%-10.3s\n", x
}

算術演算

# Numeric Functions
# AWK has the following built-in arithmetic functions:
##################################################################################
# atan2(y, x)   Returns the arctangent of y/x in radians.
# cos(expr)     Returns the cosine of expr, which is in radians.
# exp(expr)     The exponential function.
# int(expr)     Truncates to integer.
# log(expr)     The natural logarithm function.
# rand()        Returns a random number N, between 0 and 1, such that 0 <= N < 1.
# sin(expr)     Returns the sine of expr, which is in radians.
# sqrt(expr)    The square root function.
# srand([expr]) Uses  expr  as  a  new seed for the random number generator.
# If no expr is provided, the time of day is used.
# The return value is the previous seed for the random number generator.
##################################################################################

正規表現とパターンマッチング

# . ピリオドは任意の一文字を表す
# 
# * 直前の文字の 0 個以上の繰り返しを表す
#   [例]
#   ab*: a の後ろに b が 0 個以上に続く.
#   ab.*: ab の後ろに任意の文字が 0 個以上続く.
# 
# + 直前の文字の 1 個以上の繰り返し
#   [例]
#   ab+: a の後に b が 1 個以上続く.
#   ab.+: ab の後に任意の文字が 1 個以上続く.
# 
# ^ 文字列の先頭を表す
#   [例]
#   ^a: 先頭に a が来ることを表す.
#   ^ab: 先頭に ab が来ることを表す.
# 
# $ 文字列の末尾を表す
#   [例]
#   a$: 文字列が a で終わることを表す.
#   ab$: 文字列が ab で終わることを表す.
#   ^$: 空の文字列を表す.
# 
# [] [ ] の中の任意の文字を表す
#   [例]
#   [abc]: a か b か c か を表す.
#   [あ-ん]: 全てのひらがな. - で範囲を指定できる.
# 
# | 2つの正規表現の選択
#   [例]
#   ab|cd: ab か cd かを意味する.
# 
# () グループ化する
#   [例]
#   (ab|cd|ef) ab か cd か ef か を意味する.
# 
# \ 次に来る文字, それ自体を表す. 通常, メタキャラクタの前につけて,
#   そのメタキャラクタとしての意味を打ち消し, 通常の文字として
#   扱うことを意味する.
#   [例]
#   \. ピリオドそのものを表す.
#   \\ \ そのものを表す.

例文

$1 ~ /^h/{print}  # フィールド1がhで始まる行を出力

$1 !~ /e$/{ # 第 1 フィールドの単語が e で終わらないものを出力
    print FNR ":" $1
}

/^$/ {print "..."} # 改行だけの空の行を点線に換える(フィールド指定なしの場合は$0とマッチング)

文字列関数

BEGIN{
  # 文字列のバイト数を返す
  x = length("こんにちは")
  print "こんにちは: " x
  
  # マッチした文字列の開始位置(バイトで数える)
  str1 = "プログラミング言語 AWK"
  str2 = "言語"
  print "言語の開始位置: " index(str1, str2)
  
  y = match("programming", /g.*m/)
  print "g.*mの位置: " y
  print "RSTART = " RSTART   # マッチした最初の文字位置
  print "RLENGTH = " RLENGTH # マッチした部分文字列の長さ
}

条件式

BEGIN{
    str = "programming"
    if( length(str) != 10 )
      print str " の長さは 10 バイトではない"
    else
      print str " の長さは 10 バイトである"
}

# 第2フィールドが 60以上の行だけ出力する
{
    if($2 >= 60)
    print $0 # print と書くだけでもよい
}

繰り返し

# while文
# 平均点を算出するサンプル
BEGIN{
    print "氏名\t平均点" # 表の見出し
}
{
    sum = 0
    i = 2
    while(i <= NF){
    sum += $i
    i++
    }
    kaisu = NF - 1 # 試験の回数
    heikin = int(sum / kaisu)
    print $1 "\t" heikin
}

# for文
BEGIN{
    for(i = 1; i <= 10; i += 2){
    print "i = " i
    }
}

# exit文
# すべての処理を中止してEND部を実行

# next文
# 残りの処理を中断して次の行の処理へ移る

配列

BEGIN{
    name[1] = "太郎"
    name[2] = "次郎"
    name[3] = "三郎"
    for(i = 1; i <= 3; i++)
    print name[i]
}

split

# split(str, array, sep)
# str: 元の文字列
# array: 配列
# sep: 区切り文字
# 返値: 配列の要素数

BEGIN{
    longfn = "/home/kinosuke/workspacek/hogehoge/fugafuga.awk"
    num = split(longfn, arr, "/")

    for(i = 1; i <= num; i++) # 配列を出力
    print "arr[" i "]=" arr[i]
}

連想配列と数え上げ

BEGIN{
    meibutsu["大阪"] = "たこやき"
    meibutsu["名古屋"] = "きしめん"
    meibutsu["福岡"] = "辛子明太子"
    meibutsu["静岡"] = "お茶"

    for(key in meibutsu){ # key を仮引数として設定
    print key "の名物は: " meibutsu[key] # 設定した仮引数 key を用いる
    }

}

関数書ける

function add(a, b){
    return a + b
}

BEGIN{
    x = add(4, 6)
    print x
}

※注意:awkの変数はグローバル変数