はじめに
awkはテキスト処理に特化した強力なツールですが、ある程度使い慣れてくると処理が複雑になり、可読性や保守性の低下に悩む場面が増えてきます。
そこで重要になるのがfunctionの活用です。関数を使うことで処理を整理し、再利用性を高めることができます。
本記事では、初学者がつまずきやすいポイントに触れながら、実践的に理解できるよう解説していきます。
参考: GNU gawk
ユーザー定義関数の基本構文と定義場所
ファイル作成
cat << 'EOF' > input.txt
apple 100
banana 200
orange 150
EOF
実行コマンド
awk '
function add_tax(price) {
return price * 1.1
}
{
taxed = add_tax($2)
print $1, taxed
}
' input.txt
実行結果
apple 110
banana 220
orange 165
仕組み
| 要素 | 内容 |
|---|---|
| function add_tax(price) | ユーザー定義関数の宣言 |
| return price * 1.1 | 関数の戻り値(10%加算) |
| $2 | 2列目(価格)を取得 |
| taxed = add_tax($2) | 関数を呼び出して計算 |
| print $1, taxed | 商品名と計算結果を出力 |
| 定義場所 | awkスクリプト内の先頭または任意位置(処理前に解釈される) |
解説
awkでは function を使って独自の処理をまとめられます。
関数はスクリプト内のどこに書いても、実行前に読み込まれるため柔軟に配置できます。
組み込み関数とユーザー定義関数の使い分け
ファイル作成
cat << 'EOF' > input.txt
10 20
30 40
EOF
実行コマンド
awk '{print $1 + $2}' input.txt
実行結果
30
70
実行コマンド
awk '
function add(a, b) {
return a + b
}
{
print add($1, $2)
}
' input.txt
実行結果
30
70
仕組み
| 種類 | 記述方法 | 特徴 | 使用例 |
|---|---|---|---|
| 組み込み関数 | そのまま使用 | 簡潔で高速 | $1 + $2 |
| ユーザー定義関数 | function 関数名() | 再利用・可読性向上 | add(a, b) |
解説
組み込み関数はシンプルな処理に適しており、短く書けます。
複雑な処理や再利用が必要な場合はユーザー定義関数を使うのが効果的です。
戻り値の適切な活用と条件分岐による早期リターン
ファイル作成
cat << 'EOF' > input.txt
function is_valid(n) {
if (n < 0) return 0
if (n == 0) return 1
return 2
}
{
result = is_valid($1)
<code>if (result == 0) { print "negative" next } if (result == 1) { print "zero" next } print "positive"</code>
}
EOF
実行コマンド
echo -e "-1\n0\n5" | awk -f input.txt
実行結果
negative
zero
positive
仕組み
| 要素 | 内容 |
|---|---|
| function is_valid(n) | 数値の状態を判定する関数 |
| return 0 | 負の値 → 即終了(早期リターン) |
| return 1 | 0 → 即終了 |
| return 2 | 正の値 |
| result変数 | 戻り値を受け取り条件分岐に利用 |
| next | 条件成立時に後続処理をスキップ |
解説
戻り値を使うことで条件判定を関数に集約し、分岐処理がシンプルになる。
早期リターンにより無駄な処理を避け、可読性と効率が向上する。
思わぬバグを防ぐスペース区切りのテクニック
ファイル作成
cat << 'EOF' > input.txt
apple 10
banana 20
orange 30
EOF
実行コマンド
awk '{ total += $2 } END { print total }' input.txt
実行結果
60
実行コマンド
awk 'function add(x, y){ return x + y } { total = add(total, $2) } END { print total }' input.txt
実行結果
60
実行コマンド
awk '{ total += $2 } END { print "total =", total }' input.txt
実行結果
total = 60
仕組み
| 要素 | 内容 |
|---|---|
| $2 | スペース区切りで2番目のフィールド(数値)を取得 |
| total += $2 | 値を累積(スペース区切り前提) |
| function add(x, y) | awk内で関数定義し安全に加算 |
| END {} | 全行処理後に結果を出力 |
| スペース区切り | デフォルト区切りのためバグを防ぎやすい |
解説
awkはデフォルトでスペース区切りのため、余計な区切り指定を省くことでバグを防げます。
関数化することで処理の意図が明確になり、保守性も向上します。
関数の引数における「値渡し」と「参照渡し(配列)」の挙動の違い
ファイル作成
cat << 'EOF' > input.txt
function test_val(x) {
x = 100
}
function test_ref(arr) {
arr[1] = 100
}
BEGIN {
a = 1
test_val(a)
print "値渡し:", a
<code>b[1] = 1 test_ref(b) print "参照渡し(配列):", b[1]</code>
}
EOF
実行コマンド
awk -f input.txt
実行結果
値渡し: 1
参照渡し(配列): 100
仕組み
| 項目 | 渡し方 | 関数内の変更 | 呼び出し元への影響 | 理由 |
|---|---|---|---|---|
| スカラー変数 | 値渡し | 変更される | 影響なし | コピーが渡される |
| 配列 | 参照渡し | 変更される | 影響あり | 実体への参照が渡される |
解説
awkの関数ではスカラーは値渡し、配列は参照渡しとして扱われます。
そのため配列は関数内の変更が呼び出し元に反映されます。
関数内でのprint|printfを活用した変数のトレース方法
ファイル作成
cat << 'EOF' > input.txt
apple 100
banana 200
orange 150
EOF
実行コマンド
awk '
function debug_sum(x, y) {
printf("DEBUG: x=%d, y=%d, sum=%d\n", x, y, x+y)
return x + y
}
{
total = debug_sum($2, 10)
print $1, total
}
' input.txt
実行結果
DEBUG: x=100, y=10, sum=110
apple 110
DEBUG: x=200, y=10, sum=210
banana 210
DEBUG: x=150, y=10, sum=160
orange 160
仕組み
| 要素 | 内容 |
|---|---|
| function debug_sum | awkの関数定義 |
| printf | 関数内で変数の状態をトレース出力 |
| $2 | 2列目(数値)を取得 |
| total | 関数の戻り値を格納 |
| 最終結果の出力 | |
| DEBUG出力 | 処理途中の値を確認するためのログ |
解説
awkの関数内でprintfを使うことで、処理途中の変数を簡単にトレースできます。
デバッグ用途として非常に有効です。
fオプションを用いた外部ファイルからの読み込み管理
ファイル作成
cat << 'EOF' > data.txt
apple 100
banana 200
orange 150
EOF
ファイル作成
cat << 'EOF' > script.awk
function format(name, price) {
return name ": " price " yen"
}
{
print format($1, $2)
}
EOF
実行コマンド
awk -f script.awk data.txt
実行結果
apple: 100 yen
banana: 200 yen
orange: 150 yen
仕組み
| 要素 | 内容 |
|---|---|
| -f オプション | 外部ファイル(script.awk)を読み込む |
| function | awk内で独自関数を定義 |
| $1, $2 | 入力ファイルの1列目・2列目を参照 |
| 加工した結果を出力 |
解説
-fを使うことでawkスクリプトを外部ファイルとして管理でき、可読性と再利用性が向上します。
function を使うと処理を分離でき、複雑なロジックでも整理しやすくなります。
複雑な正規表現処理や数値計算のモジュール化
ファイル作成
cat << 'EOF' > input.txt
10 apple
25 banana
5 orange
30 apple
15 banana
EOF
ファイル作成
cat << 'EOF' > script.awk
# 数値計算+正規表現+関数化
function add_sum(key, value) {
sum[key] += value
}
{
# 正規表現で英字のみ抽出
if (match($2, /^[a-zA-Z]+$/)) {
add_sum($2, $1)
}
}
END {
for (k in sum) {
printf "%s: %d\n", k, sum[k]
}
}
EOF
実行コマンド
awk -f script.awk input.txt
実行結果
apple: 40
banana: 40
orange: 5
仕組み
| 要素 | 内容 |
|---|---|
| function add_sum | キーごとの合計値を加算する関数 |
| match | 正規表現で英単語のみを対象にする |
| sum配列 | 連想配列でカテゴリごとに集計 |
| ENDブロック | 最終結果を出力 |
解説
awkの関数を使うことで、数値集計ロジックを再利用可能に分離できます。
正規表現と組み合わせることで、柔軟なデータ処理が可能になります。
ディレクトリ構造や階層データの処理
ファイル作成
cat << 'EOF' > input.txt
root/child1/grandchild1
root/child1/grandchild2
root/child2/grandchild3
EOF
実行コマンド
awk -F'/' '{
for(i=1;i<=NF;i++){
printf("level%d: %s ", i, $i)
}
print ""
}' input.txt
実行結果
level1: root level2: child1 level3: grandchild1
level1: root level2: child1 level3: grandchild2
level1: root level2: child2 level3: grandchild3
実行コマンド
awk -F'/' '
function show_tree(arr, n, i, indent){
indent=""
for(i=1;i<=n;i++){
print indent arr[i]
indent=indent " "
}
print ""
}
{
split($0, parts, "/")
show_tree(parts, length(parts))
}
' input.txt
実行結果
root
child1
grandchild1
root
child1
grandchild2
root
child2
grandchild3
仕組み
| 要素 | 内容 |
|---|---|
| -F'/' | 区切り文字を / に設定 |
| split() | 文字列を配列に分解して階層構造化 |
| function show_tree | 再利用可能な処理として階層表示を定義 |
| indent | インデントを増やしてツリー構造を表現 |
| NF / length() | フィールド数(階層の深さ)を取得 |
解説
awkのfunctionを使うことで、階層データを再利用可能なロジックとして扱える。
配列とインデント制御を組み合わせるとツリー構造の可視化が簡潔に実現できる。
関数呼び出しのオーバーヘッドとメインループの設計
ファイル作成
seq 10000000 > input.txt
実行コマンド
time awk '
function square(x) {
return x * x
}
{
print square($1)
}
' input.txt
実行結果
real 0m41.943s
user 0m20.291s
sys 0m6.955s
実行コマンド
time awk '
{
print $1 * $1
}
' input.txt
実行結果
real 0m37.662s
user 0m18.461s
sys 0m6.908s
仕組み
| 項目 | 関数あり | 関数なし |
|---|---|---|
| 処理場所 | function内 | メインループ |
| 呼び出しコスト | 発生する | 発生しない |
| 可読性 | 高い | やや低い |
| 実行速度 | わずかに遅い | わずかに速い |
| 拡張性 | 高い | 低い |
解説
awkのfunctionは可読性と再利用性を高める一方、ループ内で多用すると関数呼び出しのオーバーヘッドが発生します。
高速性重視ならメインループに直接書く設計が有利です。
awkのfunctionを使いこなして保守性と可読性を高めるためのまとめ
awkにおけるfunctionの活用は、単なるテクニックではなく、コード全体の品質を左右する重要な要素です。
ユーザー定義関数を適切に設計し、組み込み関数と使い分けることで、無駄のない効率的な処理が実現できます。
また、値渡しと参照渡しの違いやスペース区切りの仕様など、細かな挙動を理解することがバグの防止につながります。
さらに、外部ファイルの活用やモジュール化によって、規模の大きな処理でも整理された構造を保つことができます。
関数の使い方を意識することで、awkは単なるワンライナーのツールから、実用的なスクリプト言語へと進化します。

![[sed] 実行して理解 指定した範囲の行を削除 文字列のsed](https://running-terminal-commands.com/wp-content/uploads/thumbnail_sed_1920_1080.png.webp)