Diary

Diary

日々学んだことをアウトプットする場として初めてみました

awk で for 文を書く

ワンライナーawk 内で for 文を回したくなることが多々あるのですが、いつも方法を忘れるのでこれを機にまとめておきたいと思います。

基本的な使い方

基本は、

for( i=<start>; i<=<end>; <increment> ){ action }

の形をしており、他の言語と似ていると思われます。

以下では 1 から 5 までループを回し、そのインデックスを出力させています。

$ awk 'BEGIN{for(i=1; i<=5; i++){print i}}'
1
2
3
4
5

余談ですが、上記のように入力を何も取らず awk のみで機能を試したい時は、 に BEGIN を与えると楽に実行できます。

各行の和を求める

次に、少し実践的な内容として、「数字が横に並んでいてその和を求める」といったことをやってみます。

イメージとしては

1 2 3

という入力に対し、

1+2+3 = 6

と答えるようなものを考えます。

$ echo '1 2 3 4 5 6 7 8 9 10' 
1 2 3 4 5 6 7 8 9 10

$ echo '1 2 3 4 5 6 7 8 9 10' | \
awk '{for(i=1; i<=NF; i++){ sum+=$i }}END{ print sum }'
55

フィールド(列)の数だけループを回し、sum という変数に値を追加しています。awk の変数は明示されなければ、0で初期化されるという特徴があります。

各フィールドには $i という方法でアクセスできます。

また、awk 内部の特殊な変数として、行におけるフィールドの総数 NF が用意されており、ループを回す条件として利用することが多いです。

ただ、上の例であれば awk を使わずに以下のように bc を用いる方が楽だと思います。

$ echo '1 2 3 4 5 6 7 8 9 10' |\
 tr ' ' '+' | bc
55

# bc の基本的な使い方
$ echo '4*3' | bc
12
# それに合わせて tr を使って変形してあげる
$ echo '1 2 3 4 5 6 7 8 9 10' |\
 tr ' ' '+'
1+2+3+4+5+6+7+8+9+10

(おまけ)九九表を作る

$ awk 'BEGIN{for(i=1; i<=9; i++){for(j=1; j<=9; j++){printf"%2s\n",i*j}}}' \
| paste -d ' ' - - - - - - - - -
 1  2  3  4  5  6  7  8  9
 2  4  6  8 10 12 14 16 18
 3  6  9 12 15 18 21 24 27
 4  8 12 16 20 24 28 32 36
 5 10 15 20 25 30 35 40 45
 6 12 18 24 30 36 42 48 54
 7 14 21 28 35 42 49 56 63
 8 16 24 32 40 48 56 64 72
 9 18 27 36 45 54 63 72 81

おわりに

他の言語と同じように for 文を使いこなせるようになると、ワンライナーでできる幅が広がると思います。是非自分の思い通りにループを回せるようになりましょう。