awkについて簡単整理
Linuxのテキスト処理ツールであるawkについて簡単に整理します。
awkはポイントさえ掴めば分かりやすいと思います。
awkは何者?
テキストデータから行を読み込み、文字列操作を行うLinuxのツールです。
特定条件にマッチする行から列を抽出し、ある処理を実行するといったバッチ処理に向いています。
個人的にはsedより文法(C like)が分かりやすい印象です。
ただ、簡単な処理の場合、sedより記述量が多くなるので、場合によって使い分けた方がいいでしょう。
コマンド
# テストファイル生成 echo a 1 >> test.txt echo b 2 >> test.txt # awk '処理内容' テキストファイル awk '{ print $0 }' test.txt # 結果) # a 1 # b 2 # テキストファイルの代わりにパイプで入力 cat test.txt | awk '{ print $1 }' # 結果) # a # b # 処理内容をファイル(awk)に入れて実行。 echo ' /a/{ print "bingo! -> ", $0 } ' > test.awk awk -f test.awk test.txt # 結果) # bingo! -> a 1
プログラム構造
# テキスト行を読み込む前に一回のみ、実行されるブロック。初期化などを記述します。 BEGIN { # コメントです。 # ... 処理内容 ... } # パターンに一致する行ごとに実行されるブロック。 /パターン/ { # ... 処理内容 ... # 変数はブロック内で宣言なしで使用できる。 # グローバルスコープなので、前の行で使用した変数を次の行でも参照・更新できる。 cnt = cnt + 1 # for, whileなどの繰り返し文も使用可能です。 for (i = 0; i < NF; i++) { ... } } # 論理条件(例 : a == 1 || NF == 3)に一致する行ごとに実行されるブロック。 論理条件 { # ... 処理内容 ... } # 全ての行ごとに実行されるブロック。 { # ... 処理内容 ... } # 最後の行の処理が終わって一回のみ、実行されるブロック。 END { # ... 処理内容 ... }
行内変数
- $0 : 現在の行の文字列
- $1~$x : 現在の行でx番目の列の文字列
他にも色々あります。参考のリンクを参照して下さい。
組込変数
- NR : 現在の行の番号
- NF : 現在の行の列数
- FS : 入力時の区切り文字。デフォルトは半角スペース。BEGINブロックでFS = "¥t"のように設定できる。
- OFS : 出力時の区切り文字。デフォルトは半角スペース。BEGINブロックでOFS = "¥t"のように設定できる。
他にも色々あります。参考のリンクを参照して下さい。
組込コマンド
- print : 文字列を出力する
# 1番目の列を出力する。 cat test.txt | awk '{ print $1 }' # 結果: # a # b # 1番目の列と2番目の列をOFS(出力時の区切り文字)で区切って出力する。 cat test.txt | awk '{ print $1, $2 }' # 結果: # a 1 # b 2 # 1番目の列と2番目の列を/で区切って出力する。 cat test.txt | awk '{ print $1 "/" $2 }' # 結果: # a/1 # b/2
他にも色々なコマンドがあります。参考のリンクを参照して下さい。
サンプル
キューにたまっているメールのうち、宛先メールアドレスのドメインがtest.testに該当するメールのキューID及びメールアドレスを抽出するサンプル。
# 以下はmailqコマンドで出力したキュー内容の例) # メール一件当たり4行です。 # -Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient------- <--- ヘッダー # ABCDEF1234 7681 Fri Jun 23 18:59:27 hogehoge@test.test <--- x行目 # (connect to dukelab.test[192.168.0.15]:25: Connection refused) <--- x+1行目 # darekasan@test.test <--- x+2行目 # <--- x+3行目 # ... 省略 ... # x行目の1列目がキューID(ABCDEF1234)です。 # x+2行目の1列目が宛先メールアドレス(darekasan@test.test)です。 # x+3行目はただの改行です。 echo ' # x行目。 # NF == 7(x行目は7つの列で構成)のように列数で判断するのもいいでしょう。 NR % 4 == 2 { # x行目なら、キューIDを抽出する。 queue_id = $1 } # x+2行目に宛先メールアドレスがある。 # NF == 1(x+2行目は1つの列で構成)のように列数で判断するのもいいでしょう。 NR % 4 == 0 && /@test.test/{ # キューID メールアドレスを出力 print queue_id OFS $1 }' > extract_qids.awk mailq | awk -f extract_qids.awk # 以下のように変数に入れてfor文で回したら、バッチ処理も可能でしょう。 # queue_ids=`mailq | awk -f extract_qids.awk` rm extract_qids.awk # 結果例 # ABCDEF1234 darekasan@test.test # ... 省略 ...