はじめに
コマンドラインでのデータ処理を学び始めると、多くの人がawkに触れることになります。
その中でもarrayの扱いは非常に重要ですが、初学者にとっては少し分かりにくいポイントでもあります。
本記事では、awkにおけるarrayの基本から実践的な使い方までを、つまずきやすいポイントを押さえながら丁寧に解説します。
参考:GNU awk
配列の基本的な宣言と初期化のルール
ファイル作成
cat << 'EOF' > input.txt
apple 100
banana 200
apple 150
orange 300
banana 50
EOF
実行コマンド
awk '{ arr[$1] += $2 } END { for (key in arr) print key, arr[key] }' input.txt
実行結果
apple 250
banana 250
orange 300
仕組み
| 要素 | 内容 |
|---|---|
| arr[$1] | $1(1列目)をキーとする配列 |
| += $2 | $2(2列目)を値として加算 |
| awk の配列 | 連想配列(キーは文字列OK) |
| END | 全行処理後に実行 |
| for (key in arr) | 配列の全キーをループ |
解説
awkの配列は連想配列として動作し、キーを指定するだけで自動的に初期化されます。
そのため事前の宣言なしで加算処理が可能です。
連想配列の仕組みとキーの概念
ファイル作成
cat << 'EOF' > input.txt
apple 100
banana 200
apple 150
orange 300
banana 50
EOF
実行コマンド
awk '{ sum[$1] += $2 } END { for (k in sum) print k, sum[k] }' input.txt
実行結果
apple 250
banana 250
orange 300
仕組み
| 要素 | 内容 |
|---|---|
| 配列名 | sum |
| キー | $1(1列目:apple などの文字列) |
| 値 | $2(数値)を加算して保持 |
| 動作 | 同じキーごとに値を累積 |
| ENDブロック | 全処理後にキーごとの合計を出力 |
解説
awkの配列は連想配列で、キーに文字列を使えるのが特徴です。 同じキーに対して自動的に値がまとめられるため、集計処理が簡潔に書けます。
for (index in array) を使った効率的なループ処理
ファイル作成
cat << 'EOF' > input.txt
apple 3
banana 5
apple 2
orange 4
banana 1
EOF
実行コマンド
awk '{ arr[$1] += $2 } END { for (i in arr) print i, arr[i] }' input.txt
実行結果
apple 5
banana 6
orange 4
仕組み
| 要素 | 内容 |
|---|---|
| $1 | 1列目(キー) |
| $2 | 2列目(加算値) |
| arr[$1] += $2 | キーごとに値を累積 |
| END | 全行処理後に実行 |
| for (i in arr) | 配列の全キーをループ |
| print i, arr[i] | キーと合計値を出力 |
解説
awkの連想配列を使うことで、キー単位の集計を1パスで効率よく処理できます。for (i in arr) により、動的に生成されたキーを簡潔に走査できます。
特定の要素が存在するか確認
ファイル作成
cat << 'EOF' > input.txt
apple
banana
orange
apple
grape
EOF
実行コマンド
awk '
{
arr[$1]++
}
END {
if ("apple" in arr) {
print "apple exists"
} else {
print "apple does not exist"
}
}' input.txt
実行結果
apple exists
仕組み
| 要素 | 内容 |
|---|---|
| arr[$1]++ | 各行の値をキーとして配列に格納しカウント |
| "apple" in arr | 配列に特定キーが存在するか確認 |
| END | 全行処理後に判定を実行 |
解説
awkの連想配列はキーが存在した時点で自動生成されるため、inでシンプルに存在確認が可能です。
カウント処理と組み合わせることで効率よく判定できます。
delete関数による配列要素の削除とメモリ管理
ファイル作成
cat << 'EOF' > input.txt
A 10
B 20
C 30
D 40
EOF
実行コマンド
awk '
{
arr[NR] = $2
}
END {
delete arr[2]
for (i=1;i<=NR;i++) {
if(i in arr) print i, arr[i]
}
}' input.txt
実行結果
1 10
3 30
4 40
仕組み
| 処理内容 | 説明 |
|---|---|
| arr[NR] = $2 | 行番号をキーに値を格納 |
| delete arr[2] | 指定キーの要素を削除 |
| for (i=1;i<=NR;i++) | 数値順でループ |
| if(i in arr) | 存在するキーのみ出力 |
解説
数値ループ+in判定により、順序を保ったまま削除要素をスキップできます。ハッシュ順に依存しない安定した出力方法です。
split関数を利用して文字列から配列を生成
ファイル作成
cat << 'EOF' > input.txt
apple,banana,grape
dog,cat,bird
EOF
実行コマンド
awk '{ n = split($0, arr, ","); for(i=1;i<=n;i++) print arr[i] }' input.txt
実行結果
apple
banana
grape
dog
cat
bird
仕組み
| 要素 | 内容 |
|---|---|
| split($0, arr, ",") | 文字列をカンマで分割し配列arrに格納 |
| n | 分割後の要素数 |
| arr[i] | 分割された各要素 |
| for文 | 配列の要素を順に処理 |
解説
split関数を使うことで、任意の区切り文字で文字列を明示的に配列へ分割できます。
返り値で要素数を取得できるため、ループ処理と相性が良いです。
多次元配列のシミュレーションとSUBSEP変数の役割
ファイル作成
cat << 'EOF' > input.txt
A 1 x
A 2 y
B 1 z
B 2 w
EOF
実行コマンド
awk '{
key = $1 SUBSEP $2
arr[key] = $3
}
END {
for (k in arr) {
split(k, idx, SUBSEP)
printf("arr[%s][%s] = %s\n", idx[1], idx[2], arr[k])
}
}' input.txt
実行結果
arr[A][1] = x
arr[A][2] = y
arr[B][1] = z
arr[B][2] = w
実行コマンド
awk 'BEGIN { print "SUBSEP =", SUBSEP }'
実行結果
SUBSEP =
仕組み
| 要素 | 内容 | 役割 |
|---|---|---|
| arr[key] | 1次元配列 | awkは本来多次元配列を持たない |
| SUBSEP | 区切り文字(デフォルトは\034) | 複数キーを1つに結合 |
| $1 SUBSEP $2 | キー生成 | 擬似的に2次元配列を実現 |
| split() | キー分解 | 元のインデックスへ復元 |
解説
awkでは多次元配列は内部的に文字列キーで管理され、SUBSEPがその結合ルールを担います。
この仕組みにより、柔軟に任意次元の配列をシミュレートできます。
ENDブロックでの配列集計結果の出力方法
ファイル作成
cat << 'EOF' > input.txt
apple 10
banana 20
apple 15
orange 5
banana 25
EOF
実行コマンド
awk '{ sum[$1] += $2 } END { for (i in sum) print i, sum[i] }' input.txt
実行結果
apple 25
banana 45
orange 5
仕組み
| 要素 | 内容 |
|---|---|
| $1 | 1列目(キー:果物名) |
| $2 | 2列目(値:数値) |
| sum[$1] += $2 | 配列にキーごとに加算 |
| END | 全行処理後に実行 |
| for (i in sum) | 配列の全キーをループ |
| print i, sum[i] | 集計結果を出力 |
解説
awkの連想配列を使うことで、キーごとに自動集計ができます。
ENDブロックでまとめて出力するのが定番パターンです。
ログファイルから重複IPアドレスをカウント・抽出
ファイル作成
cat << 'EOF' > access.log
192.168.0.1 - - [04/May/2026:10:00:00]
192.168.0.2 - - [04/May/2026:10:01:00]
192.168.0.1 - - [04/May/2026:10:02:00]
192.168.0.3 - - [04/May/2026:10:03:00]
192.168.0.2 - - [04/May/2026:10:04:00]
192.168.0.1 - - [04/May/2026:10:05:00]
EOF
実行コマンド
awk '{count[$1]++} END {for (ip in count) if (count[ip] > 1) print ip, count[ip]}' access.log
実行結果
192.168.0.1 3
192.168.0.2 2
仕組み
| 要素 | 内容 |
|---|---|
| $1 | IPアドレス(1列目) |
| count[$1]++ | IPごとに配列でカウント |
| END | 全行処理後に実行 |
| for (ip in count) | 配列のキー(IP)をループ |
| if (count[ip] > 1) | 重複のみ抽出 |
| print ip, count[ip] | IPと出現回数を表示 |
解説
awkの連想配列を使うことで、IPごとの出現回数を効率よく集計できます。
1パスでカウントと抽出が完結するため、大きなログでも高速に処理可能です。
2つのファイルを共通のキーで結合(JOIN)する配列活用術
ファイル作成
cat << 'EOF' > file1.txt
1 Alice 25
2 Bob 30
3 Carol 28
EOF
ファイル作成
cat << 'EOF' > file2.txt
1 Tokyo
2 Osaka
4 Fukuoka
EOF
実行コマンド
awk 'NR==FNR {a[$1]=$2; next} ($1 in a) {print $1, a[$1], $2, $3}' file2.txt file1.txt
実行結果
1 Tokyo Alice 25
2 Osaka Bob 30
仕組み
| ステップ | 内容 | 説明 |
|---|---|---|
| 1 | NR==FNR | 最初のファイル(file2.txt)を処理 |
| 2 | a[$1]=$2 | キー($1)で配列に値($2)を格納 |
| 3 | next | 次の行へ |
| 4 | ($1 in a) | file1のキーが配列に存在するか確認 |
| 5 | JOIN結果として出力 |
解説
awkの連想配列を使うことで、キーを軸に高速なJOIN処理が可能です。
SQLの内部結合のような動きをシンプルなワンライナーで実現できます。
awkでarrayを使いこなすためのポイントまとめ
awkにおけるarrayは、単なる配列ではなく連想配列としての柔軟性を持つ強力な機能です。
宣言不要という特性やキーの自由度、forループやin演算子による操作など、基本を理解することで応用範囲は大きく広がります。
特にログ解析やデータ集計、ファイル結合といった実務シーンでは欠かせない存在です。
初学者のうちは挙動の曖昧さに戸惑うこともありますが、一つひとつのルールを丁寧に押さえていけば、確実に実践で使えるスキルになります。
![[sed] 実行して理解 指定した範囲の行を削除 文字列のsed](https://running-terminal-commands.com/wp-content/uploads/thumbnail_sed_1920_1080.png.webp)