はじめに
テキスト処理の世界に足を踏み入れると、必ずと言っていいほど出会う強力なツールがawkです。一行ずつデータを読み込み、パターンに一致する行を処理するというシンプルな基本ループは非常に強力ですが、複雑な集計や外部データの参照が必要になると、その「自動的な一行読み込み」がもどかしく感じることがあります。そこで登場するのがgetlineです。
本記事では、初学者が直面しやすい壁を一つずつ取り除きながら、この関数の使い方を解説します。標準的なループの流れをあえて制御し、自由自在にデータを引き出すテクニックを身につければ、あなたのスクリプトの柔軟性は飛躍的に向上するはずです。
参考:GNU awk
awkの基本ループとgetlineによる介入のメカニズム
ファイル作成
cat << 'EOF' > input.txt
line1
line2
line3
EOF
実行コマンド
awk '{ print $0 }' input.txt
実行結果
line1
line2
line3
実行コマンド
awk '{
print "現在行:", $0
if (getline next_line) {
print "getline取得:", next_line
}
}' input.txt
実行結果
現在行: line1
getline取得: line2
現在行: line3
仕組み
| 項目 | 内容 |
|---|---|
| 通常ループ | awkは1行ずつ自動で読み込み処理する |
| getline | 次の行を明示的に取得し、処理の流れに介入する |
| 行の進み方 | getlineを使うと内部ポインタが進むため、通常ループに影響する |
| 変数格納 | getlineで取得した行は指定変数(例: next_line)に入る |
解説
getlineは「自動ループに割り込んで次の行を先読みする仕組み」です。
そのため、使い方次第で行スキップや複雑な制御が可能になります。
getlineの戻り値(1, 0, -1)に基づくエラーハンドリングと終了判定
ファイル作成
cat << 'EOF' > input.txt
line1
line2
EOF
実行コマンド
awk '{
while ((ret = getline line) >= 0) {
if (ret == 1) {
print "OK:", line
} else if (ret == 0) {
print "EOF reached"
break
} else if (ret == -1) {
print "Error occurred"
}
}
}' input.txt
実行結果
OK: line2
EOF reached
仕組み
| 戻り値 | 意味 | 動作内容 |
|---|---|---|
| 1 | 正常に1行読み込んだ | 読み込んだ内容を処理 |
| 0 | EOF(ファイル終端) | ループ終了の判定に使用 |
| -1 | エラー発生 | エラーハンドリングを実行 |
解説
awk getlineは戻り値で状態を判定できるため、明示的にEOFやエラー処理を書けます。
特にバッチ処理では-1の検出を入れておくと堅牢性が上がります。
外部ファイルからのデータ読み込み
ファイル作成
cat << 'EOF' > input.txt
apple 100
banana 200
orange 300
EOF
実行コマンド
awk '{ getline line < "input.txt"; print "read:", line }' input.txt
実行結果
read: apple 100
read: banana 200
read: orange 300
仕組み
| 要素 | 説明 |
|---|---|
| awk | テキスト処理ツール |
| getline line < "input.txt" | 外部ファイルから1行読み込み、変数lineに格納 |
| < "input.txt" | 標準入力とは別のファイルを指定 |
| 読み込んだ内容を出力 | |
| 繰り返し | awkの各行処理ごとにgetlineが実行される |
解説
getlineを使うことで、現在処理中の入力とは別に外部ファイルからデータを読み込めます。
ファイルを順次読み進めるため、ループごとに1行ずつ取得されます。
変数への格納による$0(カレントレコード)の保護と使い分け
ファイル作成
cat << 'EOF' > input.txt
A 100
B 200
C 300
EOF
実行コマンド
awk '{
line = $0
if ((getline next_line) <= 0) {
next_line = ""
}
print "current:", line, "| next:", next_line
}' input.txt
実行結果
current: A 100 | next: B 200
current: C 300 | next:
仕組み
| 要素 | 内容 |
|---|---|
| $0 | 現在処理中の行(カレントレコード) |
| line = $0 | $0を変数に退避(保護) |
| getline | 次の行を読み込み、$0を上書き |
| next_line | getlineで取得した次の行を保持 |
| 問題点 | getlineすると元の$0が消える |
| 解決策 | 事前に変数へ保存して使い分け |
解説
getlineは$0を上書きするため、そのままだと元の行が失われる。
事前に変数へ退避することで、現在行と次行を安全に扱える。
パイプ経由でのコマンド実行結果の取得
ファイル作成
cat << 'EOF' > input.txt
apple
banana
cherry
EOF
実行コマンド
echo "dummy" | awk '{ "cat input.txt" | getline line; print line }'
実行結果
apple
実行コマンド
echo "dummy" | awk '{ "cat input.txt" | getline line; print line; "cat input.txt" | getline line; print line }'
実行結果
apple
banana
仕組み
| 要素 | 内容 |
|---|---|
| "cat input.txt" | getline line | 外部コマンドを実行し、その出力を1行取得 |
| getline | パイプから1行ずつ読み込む |
| line | 読み込んだ内容を格納する変数 |
| print line | 取得した行を出力 |
| 繰り返しgetline | 次の行を順次取得可能 |
解説
awkのgetlineは外部コマンドの出力を直接取り込めるため、パイプ経由のデータ処理に柔軟性を持たせられます。
複数回呼び出すことで、ストリームを順次読み進めることができます。
また、echo dummyはawkを1回起動するためのトリガーとして機能します。
BEGINブロックにおける初期設定ファイルの先読みテクニック
ファイル作成
cat << 'EOF' > config.txt
name=John
age=30
EOF
ファイル作成
cat << 'EOF' > input.txt
data1
data2
EOF
実行コマンド
awk 'BEGIN {
while ((getline line < "config.txt") > 0) {
split(line, a, "=")
conf[a[1]] = a[2]
}
}
{
print $0, conf["name"], conf["age"]
}' input.txt
実行結果
data1 John 30
data2 John 30
仕組み
| フェーズ | 処理内容 | awk getlineの役割 |
|---|---|---|
| BEGIN | config.txtを1行ずつ読む | 入力本体とは別ファイルを先読み |
| BEGIN | splitでキーと値に分割 | 設定値を配列へ格納 |
| メイン処理 | input.txtを1行ずつ処理 | 事前に読み込んだ設定を利用 |
| 出力 | データ+設定値を表示 | conf配列を参照 |
解説
BEGIN内でgetlineを使うことで、メイン入力処理前に設定ファイルを読み込める。
これにより、擬似的な初期設定ファイルの仕組みをawk単体で実現できる。
複数ファイル操作時の必須処理
ファイル作成
cat << 'EOF' > input.txt
A 1
B 2
C 3
EOF
ファイル作成
cat << 'EOF' > ref.txt
A Apple
B Banana
C Cherry
EOF
実行コマンド
awk 'NR==FNR { map[$1]=$2; next } { print $0, map[$1] }' ref.txt input.txt
実行結果
A 1 Apple
B 2 Banana
C 3 Cherry
実行コマンド
awk '{ getline line < "ref.txt"; split(line, a, " "); print $0, a[2] }' input.txt
実行結果
A 1 Apple
B 2 Banana
C 3 Cherry
仕組み
| 要素 | 内容 |
|---|---|
| NR==FNR | 最初のファイル(ref.txt)読み込み時のみ処理 |
| map配列 | キー($1)に対応する値($2)を保持 |
| getline | 別ファイルから1行ずつ読み込む |
| split | 読み込んだ行を配列に分割 |
| next | 次のレコードへスキップ |
解説
awk getline を使うことで別ファイルを逐次読み込みでき、複数ファイルを同時に扱う処理が可能になります。
ただし、対応関係がある場合は配列で事前に読み込む方法のほうが安全で一般的です。
getline を使うべき場面とnextで十分な場面
ファイル作成
cat << 'EOF' > input.txt
A 1
B 2
C 3
EOF
実行コマンド
awk '{
print $0;
if(getline > 0) {
print "next line:", $0
} else {
print "next line:"
}
}' input.txt
実行結果
A 1
next line: B 2
C 3
next line:
実行コマンド
awk '{ print $0; next }' input.txt
実行結果
A 1
B 2
C 3
仕組み
| 機能 | 動作内容 | レコード消費 | 主な用途 |
|---|---|---|---|
| getline | 次の行を明示的に読み込み、$0を上書き | する | 先読み・複数行処理 |
| next | 現在行の処理を終了し次のレコードへ進む | する | 単純なスキップ・高速処理 |
解説
getline は「次の行を自分で取りにいく」制御が必要な場面で使う。
next は「今の処理を打ち切るだけ」で十分なシンプルなケースに向いている。
無限ループを防ぐための条件式の書き方
ファイル作成
cat << 'EOF' > input.txt
line1
line2
line3
EOF
実行コマンド
awk '{
count=0
while ((getline next_line) > 0) {
print $0 " -> " next_line
count++
if (count > 2) break
}
}' input.txt
実行結果
line1 -> line2
line1 -> line3
仕組み
| 要素 | 内容 |
|---|---|
| getline | 次の行を読み込んで変数に格納する |
| while ((getline) > 0) | EOFまでループする条件 |
| count変数 | ループ回数を制御する |
| break | 一定回数で強制終了し無限ループ防止 |
| $0 | 現在行の内容 |
| next_line | getlineで取得した次の行 |
解説
awk getlineは条件なしだとEOFまで読み続けるため無限ループになりやすいです。
回数制御やbreakを組み合わせるのが安全です。
複数ファイルの特定列を結合・比較するデータ処理
ファイル作成
cat << 'EOF' > file1.txt
A 100
B 200
C 300
EOF
ファイル作成
cat << 'EOF' > file2.txt
A apple
B banana
D durian
EOF
実行コマンド
awk 'NR==FNR { data[$1]=$2; next } { if ($1 in data) print $1, data[$1], $2; else print $1, "N/A", $2 }' file1.txt file2.txt
実行結果
A 100 apple
B 200 banana
D N/A durian
実行コマンド
awk '{
while ((getline line < "file1.txt") > 0) {
split(line, a, " ")
if ($1 == a[1]) {
print $1, a[2], $2
found=1
break
}
}
close("file1.txt")
if (!found) print $1, "N/A", $2
found=0
}' file2.txt
実行結果
A 100 apple
B 200 banana
D N/A durian
仕組み
| 処理ステップ | 内容 |
|---|---|
| ファイル読込1 | 1つ目のファイル(file1.txt)を連想配列に格納 |
| キー抽出 | 1列目をキーとして扱う |
| 照合処理 | 2つ目のファイル(file2.txt)とキー一致を確認 |
| 結合処理 | 一致時は値を結合、不一致はN/A |
| getline版 | file2.txt処理中にfile1.txtを逐次読み込み比較 |
解説
NR==FNRを使う方法は高速で一般的、getlineは逐次比較の仕組み理解に向いています。
どちらも特定列をキーにした結合処理の基本パターンです。
awkとgetlineを駆使した効率的なデータ制御
awkの基本ループというレールから一歩踏み出し、getlineによる能動的なデータ制御を学ぶことは、初学者が中級者へとステップアップするための大きな関門です。$0の保護や戻り値のチェック、そして適切なclose処理。これらは一見細かいルールに見えますが、大規模なデータを正確に、かつ高速に処理するためには欠かせない知識です。
自動化されたループの利便性を享受しつつ、ここぞという場面でgetlineを介入させる。このバランス感覚を磨くことで、あなたのコマンドラインでの作業効率は劇的に向上することでしょう。今回紹介したテクニックを、ぜひ日々のログ解析やレポート作成に役立ててみてください。
![[sed] 実行して理解 指定した範囲の行を削除 文字列のsed](https://running-terminal-commands.com/wp-content/uploads/thumbnail_sed_1920_1080.png.webp)