generated at
awk

基本文法
パターンに対応するアクションを行う
basic.awk
BEGIN { 前処理 } パターン1 { アクション1 } パターン2 { アクション2 } ... END { 後処理 }

パターン=条件式
条件式の返り値の真偽値に基づいてアクションを実行する
真偽値
数字(≠文字列)の0
空文字列
それ以外

真偽値.sh
$ echo foo | awk '0 {print $1}' (何も表示されない) $ echo foo | awk '1 {print $1}' foo

1オリジン
awk では配列の要素数やレコードなどは 1 から始まる



区切り文字
区切り文字のデフォルトは空白かタブ文字
区切り文字の変更
-F で変更可能
-F, でカンマを区切り文字にする。
-F"[:,]" で複数指定可能


レコード
組み込み変数 RS(Record Separator) で区切られた行のこと
awk の処理単位


変数
フィールド変数
先頭が $
{print $1} で一個目のフィールドを出力
{print $0} は行全体
通常の変数
{a=5; print a;} 変数 a に 5 を代入して出力
{a=5; print $a;} フィールド変数 $5 と同じ


代入
$1 = "A" 第1フィールドを A に上書き
代入の返り値
左辺値が返り値となる
代入の返り値.sh
$ echo "a b c" | awk '{print $2 = "B"}' B $ echo "a b c" | awk '{print $2 = ""}' (何も表示されない)


組み込み変数
組み込み変数
変数名説明サンプル意味
FSセパレータ指定(-F と同じ)FS="\t"タブ文字を区切り文字に指定
NFフィールド数{ print $NF }最後のフィールドをプリント
NR行数END { print $NR }処理した行数を表示
RS行の区切り文字(デフォルトは改行文字"\n")
ORSprint時の改行文字(デフォルトは改行文字"\n")
FILENAME処理中のファイル名
OFMT数値の出力形式
OFSprint関数での区切り(OutputFieldSeparator)print $1, $2print内の","の置き換え(デフォルトでスペース)
length行の文字総数


パターン指定
正規表現
awk '/正規表現/ { アクション }' (先頭に $0 ~ が暗黙的に付与される)
特定フィールドが正規表現に一致したもの
awk '$n ~ /正規表現/ { アクション }'
特定フィールドが正規表現に一致しないもの
awk '$n !~ /正規表現/ { アクション }'
空行を飛ばす
awk 'NF > 0 { アクション }'
$ cat foo.txt | awk 'NF' (フィールド数が0の行が となりスキップされる)
先頭10〜20行を抜き出す
$ seq 1 100 | awk 'NR >= 10 && NR <= 20'
末尾10行を抜き出す( tail もどき)
awk は先頭から順に読み込むため、素直に実装すると非効率
リングバッファ的なものを利用する
$ seq 1 100 | awk '{ a[NR % 10] = $0 } END { for(i = NR + 1; i <= NR + 10; i++) print a[i % 10]}


文字列の操作
結合
awk '{print "a" "b"}' 並べればOK
数値の文字列化
awk '{ print 0 "" }' 文字列と連接させて明示的に文字列として扱う


三項演算子
awk '{ ORS = NR % n ? "," : "\n"; print}'
ORS ( print の末尾) を n で割った余りが 0 の時 \n が設定される


範囲演算子
範囲を指定する演算子
awk 'NR == 10, NR == 20' 10行目から20行目まで になる
正確な動作
スイッチのような動作
NR == 10 になったらパターンを真にして NR == 20 になったらパターンを偽にする(を繰り返す)
awk '真になるパターン, 偽になるパターン'
seq 1 10 | awk 'NR % 2 == 0, NR % 3 == 0' を実行すればわかる


処理のスキップ
next 命令を使う
awk 'NF == 1 { next }' 最初の行を飛ばす


関数
awk の関数は一価関数
返り値は1つのみ
関数例.sh
$ echo "a b c" | awk '{ print(length) }' # length は () が省略できる特殊な関数(暗黙的に$0を見る) 5

関数
関数名効果返り値
sub(/正規表現/, "文字列")文字列の置換(最初のみ)成功:1/失敗0
gsub(/正規表現, "文字列")文字列の置換(マッチしたところ全部)成功した個数を数値
split("文字列", arr)文字列の分割分割個数
substr($N, m:int, n:int)m文字目からn文字抜き出す(n省略時は全部)抜き出した文字列
index($N, "文字列")文字列が最初に出現する箇所を数値で返す最初に出現した位置
toupper("文字列")大文字変換変換した文字列
tolower("文字列")小文字変換変換した文字列


数値計算
値はすべて倍精度浮動小数点数として扱う






スニペット
再帰的リネーム.sh
$ find . -type f | while read FILE do echo ${FILE} | awk -F/ '{print "mv",$0, $1"/"$2"/"$3"/1."$4}' | sh done


何個マッチするか数える.sh
$ echo "ab ba ac ab" | awk '$0 = gsub(/ab/, "") ""' # 0個のときも表示したいので "" を連接させる 2

フィールドの再構築.sh
# csvのカンマ区切りをスペースに置き換える `$1 = $1` はフィールドの再構築という手法 $ echo "0, 1, 2" | awk -F, -v OFS=' ' '$1 = $1'

正規表現のマッチ部分の抜き出し.sh
$ echo 'abcdef' | awk 'match($0, /b.*e/) { print substr($0, RSTART, RLENGTH) }' bcde # 実は grep でやるほうが簡単 $ echo 'abcdef' | grep -o 'b.*e' bcde # 横一列を縦一列に $ echo 'abc' | grep -o '.' a b c

標準入力を受け取る.sh
# 標準入力を使う。ちょっとした動作確認などに便利。 $ awk '{ アクション }' -





参考文献

Volodymyr Gubarkov
awkスペシャリストのブログ

AWKのオリジナル(公式?)実装
EBNF Grammar for AWK
Golang実装
AWKで実装されたファイルマネージャ
AWKで実装されたiptableビジュアライザー
AWKでGitを実装する
awkでライフゲーム(リアルタイム処理) - utthi_fumiの日記
awkでRPGゲーム - utthi_fumiの日記
LRパーサー
CLIでGoogle翻訳を呼び出すawkスクリプト
IntelliJ-awk
frawk
>Rust による awk 言語実装.主に高パフォーマンスと CSV 対応が売り.型推論によって全ての変数の型を静的に明らかにし SSA 形式の IR に変換 → LLVM で JIT コンパイルする.レコード単位での処理の並列実行をサポート
AWKを始めとするコマンドラインテキスト処理についてのまとめ
awk with csv
Old school Awk
awk の基本的なデモスクリプト集
Modernizing AWK, a 45-year old language, by adding CSV support
Understanding AWK - Earthly Blog

The AWK State Machine Parser Pattern
Grep, sed and awk – The Right Tool For The Job
grep, sed, awk の使い分けの基本的指針