MENU

初心者向けawkコマンドの使い方

目次

awkコマンドとは

awk(オーク)はテキストを1行ずつ読みながら、1行をくつかの列(フィールド)に分けて読む・抜き出す・加工するためのコマンド。
たとえば、ログの「3列目だけ取りたい」時にawkが便利。

awkの基本構文

awk の基本構文は以下。

awk 'パターン { アクション }' ファイル名

パターン=どんな行を選ぶか
アクション=その行で何をするか

ざっくり言うと 「ファイルの中で、〇〇な行があったら、△△をする」。

awkの基本をサンプルから覚える

サンプル

サンプルとして使用するファイルの内容。
各行は「名前・年齢・都市・職業」の4つのフィールドで構成されている。

# sample.txt
Alice   25  Tokyo     Engineer
Bob     30  Osaka     Manager
Charlie 28  Nagoya    Designer
David   35  Fukuoka   Engineer
Eve     22  Tokyo     Intern

サンプルファイルの分解

タブやスペースごとに awk が自動で以下表のように読み込んでくれる。

フィールド番号内容(意味)awkで書くと
$1名前(Name)Alice
$2年齢(Age)25
$3都市(City)Tokyo
$4職業(Job)Engineer

実際に動かしてみる

行全体を表示

print で出力し、$0 でその行全体(すべてのフィールド)を指定。

$ awk '{print $0}' sample.txt

ファイル全体を見たいなら cat でいい気がするので、実務では使わないかも。

# sample.txt
Alice   25  Tokyo     Engineer
Bob     30  Osaka     Manager
Charlie 28  Nagoya    Designer
David   35  Fukuoka   Engineer
Eve     22  Tokyo     Intern

1列目(名前)だけ表示

$1 で名前フィールドを出力。

$ awk '{print $1}' sample.txt

これだけだとコメント(#)まで出力されてしまうので、実務ではもう少し条件を絞った方がよさそう。

#
Alice
Bob
Charlie
David
Eve

コメント(#)を除外

! = ~でない、/文字列/ = 正規表現の始まりと終わりを示す囲み記号、^ = 先頭行 の意味。
先頭行がコメント(#)でない名前フィールドを出力。

$ awk '!/^#/ {print $1}' sample.txt

コメント(#)が除外され、名前のフィールドだけが出力される。

Alice
Bob
Charlie
David
Eve

名前と都市を表示

$1 で名前フィールド、$3 で都市フィールドを指定。

$ awk '{print $1, $3}' sample.txt

それぞれのフィールドが正しく抽出されている。

# 
Alice Tokyo
Bob Osaka
Charlie Nagoya
David Fukuoka
Eve Tokyo

Tokyo に住んでいる人だけ表示

$3 を == で Tokyo 指定。

$ awk '$3 == "Tokyo" {print $0}' sample.txt

Tokyo に住んでいる人だけが抽出される。

Alice   25  Tokyo     Engineer
Eve     22  Tokyo     Intern

年齢が30歳以上の人だけ表示

$2 >= 30 で指定。ついでにコメントも && でつなげて除外しておく。

$ awk '!/^#/ && $2 >= 30 {print $1, $2}' sample.txt

30歳以上の人だけが抽出される。

Bob 30
David 35

Engineerの人数を数える

$4 == “Engineer” で エンジニアを指定、{count++} で条件が真なら count を 1 増やす、END {print count} でファイルを全部読み終わったあとに出力。

$ awk '$4 == "Engineer" {count++} END {print count}' sample.txt

きちんとカウントされている。

2

平均年齢を計算

{sum += $2; count++} で 2 列目(年齢)の値を合計し、行数を 1 増やす。
END {print sum/count} でファイルをすべて読み終えたあとに平均を出力する。
※今回はカウント処理を行うため、コメント(#)のスキップが必須。

; は改行と同じ意味。

$ awk '!/^#/ {sum += $2; count++} END {print sum/count}' sample.txt

平均年齢が出力される。

28

このコマンドの動きは以下の通り。

$2(年齢)条件 !/^#/sumの値countの値
# sample.txtFalse00
Alice 25 Tokyo Engineer25True251
Bob 30 Osaka Manager30True552
Charlie 28 Nagoya Designer28True833
David 35 Fukuoka Engineer35True1184
Eve 22 Tokyo Intern22True1405

都市ごとの人数を集計

{city[$3]++} で 3 列目(都市名)をキーとしてカウントする。
END { … } はファイルをすべて読み終えたあとに 1 回だけ実行される処理。
for (c in city) ですべての都市(キー)を順に処理し、
print c, city[c] で都市名と人数を出力する。
※今回はカウントをしているのでコメントのスキップは必須。

$ awk '!/^#/ {city[$3]++} END {for (c in city) print c, city[c]}' sample.txt 

都市ごとの人数が出力される。

Osaka 1
Fukuoka 1
Nagoya 1
Tokyo 2

このコマンドの動きは以下の通り。

$3(都市)条件 !/^#/city[$3] の動作city配列の内容(内部状態)
# sample.txtFalse実行されない(何もない)
Alice 25 Tokyo EngineerTokyoTruecity["Tokyo"]++ → 1Tokyo:1
Bob 30 Osaka ManagerOsakaTruecity["Osaka"]++ → 1Tokyo:1, Osaka:1
Charlie 28 Nagoya DesignerNagoyaTruecity["Nagoya"]++ → 1Tokyo:1, Osaka:1, Nagoya:1
David 35 Fukuoka EngineerFukuokaTruecity["Fukuoka"]++ → 1Tokyo:1, Osaka:1, Nagoya:1, Fukuoka:1
Eve 22 Tokyo InternTokyoTruecity["Tokyo"]++ → 2Tokyo:2, Osaka:1, Nagoya:1, Fukuoka:1

疑問に思ったこと

文章ベースのファイルにはawkコマンドは使えないのか

たとえば、

Aliceは東京で働いています。
Bobは大阪に住んでいます。
Charlieは28歳です。

という文章ファイルがあった場合、awk の使いどころがあるのか気になった。

awk の動きとしては「スペースやタブで明確に区切られていない」文章だと、

$1 Aliceは東京で働いています。
$1 Bobは大阪に住んでいます。
$1 Charlieは28歳です。

となり、すべて $1 になるのでフィールド分けができず、awk の長所は活かせない。

一応、grep のように抽出することは可能。

$ awk '/東京/ {print $0}' sample_text.txt
Aliceは東京で働いています。

$ awk '/[0-9]+歳/ {print $0}' sample_text.txt
Charlieは28歳です。

行番号を付けることもできる。

$ awk '{print NR, $0}' sample_text.txt
1 Aliceは東京で働いています。
2 Bobは大阪に住んでいます。
3 Charlieは28歳です。

結論としては、awk でも文章ファイルの操作はある程度できるけど、本来の用途とは離れており、わざわざ awk で文章ファイルを操作する必要はなさそう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

勉強中のセキュリティエンジニアです。
初心者の目線で学んだことをまとめています。

コメント

コメントする

CAPTCHA


目次