4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GNU awkを使う

Last updated at Posted at 2017-10-14

はじめに

GNU awk(gawk)の使い方を説明します。ここでは単にawkといいます。
awkはテキスト処理のために設計されたプログラムです。

考え方

awkは1行毎に処理を行います。ファイルの最後まで処理をしたら終了します。
パターン(pattern)にマッチしたときに処理(action)を行います。

pattern { action }

行毎の処理前、後におこなう処理は次のように指定できます。

BEGIN { action }
END { action }

sample

lsで表示される情報を空白で区切った列を抜き出します。
lsした結果です。

console
$ ls -lsa | head
合計 252
 4 drwxr-xr-x 22 user user  4096 10月  5 02:09 .
 4 drwxr-xr-x  3 root root  4096  5月  7 23:55 ..
24 -rw-------  1 user user 24468 10月  5 02:09 .ICEauthority
 4 -rw-------  1 user user   201 10月  5 02:09 .Xauthority
 4 drwx------  3 user user  4096  8月 28 22:08 .anthy
 4 -rw-r--r--  1 user user   177  5月  7 23:51 .apport-ignore.xml
32 -rw-------  1 user user 31623 10月  5 02:01 .bash_history
 4 -rw-r--r--  1 user user   220  5月  7 23:48 .bash_logout
 4 -rw-r--r--  1 user user  3647  5月  7 23:48 .bashrc

lsの結果をpipeでawkに繋げて6列を表示する例です。

console
$ ls -lsa | awk '{ print $6 } ' | head

4096
4096
24468
201
4096
177
31623
220
3647

6列は$6で参照できます。

$6="" とすることで6列を削除します。

console
$ ls -lsa | awk '{ $6=""; print $0 }' | head
合計 264    
4 drwxr-xr-x 22 user user  10月 14 22:37 .
4 drwxr-xr-x 3 root root  5月 7 23:55 ..
28 -rw------- 1 user user  10月 14 22:30 .ICEauthority
4 -rw------- 1 user user  10月 14 22:30 .Xauthority
4 drwx------ 3 user user  8月 28 22:08 .anthy
4 -rw-r--r-- 1 user user  5月 7 23:51 .apport-ignore.xml
36 -rw------- 1 user user  10月 14 10:19 .bash_history
4 -rw-r--r-- 1 user user  5月 7 23:48 .bash_logout
4 -rw-r--r-- 1 user user  5月 7 23:48 .bashrc

次に"bash"を含む行を表示する例です。

console
$ ls -lsa | awk '/bash/ { print $0 } ' | head
32 -rw-------  1 user user 31623 10月  5 02:01 .bash_history
 4 -rw-r--r--  1 user user   220  5月  7 23:48 .bash_logout
 4 -rw-r--r--  1 user user  3647  5月  7 23:48 .bashrc

パターンに/bash/を指定します。現在の行は$0で参照します。

次に"bash"を含む行の6列を合計します。

console
$ ls -lsa | awk 'BEGIN {v=0} /bash/ {print $0; v+=$6} END {print v}'
32 -rw-------  1 user user 31623 10月  5 02:01 .bash_history
 4 -rw-r--r--  1 user user   220  5月  7 23:48 .bash_logout
 4 -rw-r--r--  1 user user  3647  5月  7 23:48 .bashrc
35490

BEGINでvを初期化します。v+=$6で6列を加算します。ENDでvを表示します。

フィールドの区切りのデフォルトは空白です。

次のようにして区切り文字が変更できます。
カンマに変更する例です。

-F オプションで指定する例

console
$ cat data.txt 
taro,20,kanagawa
jiro,19,tokyo
saburo,16,chiba
$ cat data.txt | awk -F, '{ print $1 }' 
taro
jiro
saburo

FSで指定する例

console
$ cat data.txt | awk 'BEGIN { FS="," } { print $2 }' 
20
19
16

print

printで標準出力に文字列を表示できます。
次に例を示します

console
$ awk 'BEGIN { print "a","b" }'
a b
$ awk 'BEGIN { print "a""b" }'
ab
$ awk 'BEGIN { print "a" "b" }'
ab
$ awk 'BEGIN { OFS=";"; print "a","b" }'
a;b

文字列を","で繋げると文字列の間にseparatorが出力されます。
separatorはOFS変数に値を設定することで変更できます。
OFSの初期値は空白" "です。

printfを使うとC Language の printfと類似の方法で表示できます。
改行コードを明示する必要があります。

console
$ ls -lsa $HOME | head | awk '{ printf "%x %d\n", NR, NR }'
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
a 10

script file

awk programをファイルに保存してbash scriptのように利用できます。

test.awk
# !/usr/bin/awk -f

BEGIN {
    print "Hello"
}

{ print }

実行します。

console
$ ls -lsa $HOME | ./test.awk | head
Hello
合計 260
 4 drwxr-xr-x 22 user user  4096 10月 14 10:19 .
 4 drwxr-xr-x  3 root root  4096  5月  7 23:55 ..
28 -rw-------  1 user user 24850 10月 11 08:04 .ICEauthority
 4 -rw-------  1 user user   201 10月 11 08:04 .Xauthority
 4 drwx------  3 user user  4096  8月 28 22:08 .anthy
 4 -rw-r--r--  1 user user   177  5月  7 23:51 .apport-ignore.xml
36 -rw-------  1 user user 36578 10月 14 10:19 .bash_history
 4 -rw-r--r--  1 user user   220  5月  7 23:48 .bash_logout

Built-in Variables

awkには定義済みの変数があります。
次に定義済みの変数一覧を示します。

name description
$0 現在処理中の行
$1 現在の行に含まれる1番目のフィールド
$N 現在の行に含まれるN番目のフィールド
FS Field Separator ; 入力のフィールド区切り
RS Record Separator ; 入力の改行コード
OFS Output Field Separator ; 出力のフィールド区切り
ORS Output Record Separator ; 出力の改行コード
NR Number of Records ; 行番号

NR

NRはBEGINで0, 各行で行番号、ENDで行数になります。

test.awk
# !/usr/bin/awk -f

BEGIN {
    print "BEGIN NR", NR
}
{
    print NR
}

END {
    print "END NR", NR
}
console
$ ls -lsa $HOME | head | ./test.awk 
BEGIN NR 0
1
2
3
4
5
6
7
8
9
10
END NR 10

制御構造

test.awk
# !/usr/bin/awk -f

BEGIN {
    print "if"
    i = 10
    if (i == 10) {
        print "i == 10"
    } else if (i == 20) {
        print "i == 20"
    } else {
        print "else"
    }
    print

    print "for"
    for (i=0; i<3; i++) {
        print i
    }
    print
    
    print "while"
    i = 3
    while (i--) {
        print i
    }
    print
}
console
$ ./test.awk 
if
i == 10

for
0
1
2

while
2
1
0

Array

行をまたがった処理をする場合、読み込んだ行をArrayに保存しておきます。
Arrayの使い方を説明します。

test.awk
# !/usr/bin/awk -f

{
    a[NR] = $0
}

END {
    for (i=1; i<=NR; i++) {
        print a[i]
    }
}

NRは最初の行で1となります。最後の行で行数となります。
よってfor文は1から始まってNで終わっていることに注意してください。

console
$ ls -lsa $HOME | head | ./test.awk 
合計 260
 4 drwxr-xr-x 22 user user  4096 10月 14 10:19 .
 4 drwxr-xr-x  3 root root  4096  5月  7 23:55 ..
28 -rw-------  1 user user 24850 10月 11 08:04 .ICEauthority
 4 -rw-------  1 user user   201 10月 11 08:04 .Xauthority
 4 drwx------  3 user user  4096  8月 28 22:08 .anthy
 4 -rw-r--r--  1 user user   177  5月  7 23:51 .apport-ignore.xml
36 -rw-------  1 user user 36578 10月 14 10:19 .bash_history
 4 -rw-r--r--  1 user user   220  5月  7 23:48 .bash_logout
 4 -rw-r--r--  1 user user  3647  5月  7 23:48 .bashrc

配列のサイズはlengthで取得できます。

console
$ ls -lsa | head | awk '{ a[NR] = $0 } END { print length(a) }'
10

パターンマッチ

~(tidle)と//を使うことで文字列が正規表現にマッチしたかどうかを確認できます。

console
$ ls -lsa | head
合計 264
 4 drwxr-xr-x 22 user user  4096 10月 14 22:37 .
 4 drwxr-xr-x  3 root root  4096  5月  7 23:55 ..
28 -rw-------  1 user user 25232 10月 14 22:30 .ICEauthority
 4 -rw-------  1 user user   201 10月 14 22:30 .Xauthority
 4 drwx------  3 user user  4096  8月 28 22:08 .anthy
 4 -rw-r--r--  1 user user   177  5月  7 23:51 .apport-ignore.xml
36 -rw-------  1 user user 36578 10月 14 10:19 .bash_history
 4 -rw-r--r--  1 user user   220  5月  7 23:48 .bash_logout
 4 -rw-r--r--  1 user user  3647  5月  7 23:48 .bashrc
$ ls -lsa | head | awk '{ if($0~/23/) print }'
 4 drwxr-xr-x  3 root root  4096  5月  7 23:55 ..
28 -rw-------  1 user user 25232 10月 14 22:30 .ICEauthority
 4 -rw-r--r--  1 user user   177  5月  7 23:51 .apport-ignore.xml
 4 -rw-r--r--  1 user user   220  5月  7 23:48 .bash_logout
 4 -rw-r--r--  1 user user  3647  5月  7 23:48 .bashrc
$ ls -lsa | head | awk '{ if($0~/root/) print }'
 4 drwxr-xr-x  3 root root  4096  5月  7 23:55 ..

Arrayを使ってパターンマッチした行とその次の行を表示する例です。

test.awk
# !/usr/bin/awk -f

{
    a[NR] = $0
}

END {
    for (i=1; i<=NR; i++) {
        if (a[i]~/bss|data/) {
            print a[i]
            print a[i+1]
        }
    }
}

実行ファイルからrodata / data / bss sectionの情報を取り出します。

console
$ readelf -S ./a.out | ./test.awk 
  [15] .rodata           PROGBITS         0000000000400580  00000580
       0000000000000004  0000000000000004  AM       0     0     4
  [24] .data             PROGBITS         0000000000601028  00001028
       0000000000000010  0000000000000000  WA       0     0     8
  [25] .bss              NOBITS           0000000000601038  00001038
       0000000000000008  0000000000000000  WA       0     0     1
4
5
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
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?