【Linux】awkコマンドの使い方|列の抽出・-F区切り・条件・合計の集計

【Linux】awkコマンドの使い方|列の抽出・-F区切り・条件・合計の集計 Linux

awkは、テキストを行と列に分けて処理するLinuxの定番コマンドです。スペースやカンマで区切られたデータから特定の列だけを取り出したり、条件に合う行を選んだり、数値の合計を集計したりできます。grepが「行の検索」、sedが「置換」、awkは「列の処理と集計」と覚えると役割が分かりやすいです。

基本の形はawk '{print $1}'で、$1が1列目、$2が2列目を表します。つまずきやすいのは、CSVなど空白以外で区切られたデータには-Fで区切り文字の指定が必要なことです。この記事では、実機のLinux(WSLのDebian)で実際にコマンドを動かしながら、awkの使い方を整理します。

先に結論

  • 列の抽出はawk '{print $1}'$1が1列目、$2が2列目です。
  • CSVは-F,のように-Fで区切り文字を指定します(標準は空白区切り)。
  • $0は行全体、NFは列数、NRは行番号を表します。
  • 条件はawk '$2 >= 30 {print $1}'のように、{}の前に書きます。
  • 合計はawk '{sum += $2} END {print sum}'ENDは全行処理後に実行されます。
  • プログラム部分はシングルクォート'...'で囲みます。

行の検索はgrepコマンド、置換はsedコマンド、ファイル検索はfindコマンドもあわせて参考になります。

スポンサーリンク

awkの基本:列を取り出す

もっとも基本的な使い方が列の抽出です。awk '{print $1}'で1列目、$2で2列目が取り出せます。複数の列をカンマで並べることもできます。

列の抽出
# 名前 年齢 出身 が並ぶファイル
cat list.txt
# tanaka 30 tokyo
# suzuki 25 osaka

# 1列目(名前)だけを取り出す
awk '{print $1}' list.txt
# tanaka
# suzuki

# 1列目と3列目を取り出す(カンマで区切るとスペースが入る)
awk '{print $1, $3}' list.txt
# tanaka tokyo
# suzuki osaka

実機でも、awk '{print $1}' list.txtで1列目の名前だけ(tanakasuzukisato)が取り出せました。$1$2…が左からの列番号に対応し、標準ではスペースやタブが区切りとして扱われます(連続する空白は1つの区切りとみなされます)。print $1, $3のようにカンマで並べると、複数の列をスペース区切りで出力できます。ls -lps auxなど、列で整形されたコマンド出力から必要な列だけ抜くのが定番の使い方です。

区切り文字の指定 -F(CSVなど)

ここが最初の注意点です。awkの標準の区切りは空白なので、CSV(カンマ区切り)などはそのままでは列に分かれません-Fで区切り文字を指定します。

-F で区切り文字を指定
# カンマ区切りのCSV
cat items.csv
# apple,120,3
# banana,80,5

# -F, でカンマを区切りに指定
awk -F, '{print $1}' items.csv
# apple
# banana

# コロン区切り(/etc/passwd など)
awk -F: '{print $1}' /etc/passwd

# タブ区切りなら -F'\t' 
CSVには-F,が必須

実機で確認したところ、カンマ区切りのitems.csvに対してawk -F, '{print $1}'とすると、1列目のapplebananacherryが正しく取り出せました。-Fを付けないと、カンマは区切りとして扱われず、apple,120,3という行全体が「1列目」になってしまいます。「列が取れない」ときは、区切り文字が合っているかをまず確認してください。-F,(カンマ)、-F:(コロン、/etc/passwd向き)、-F'\t'(タブ)のように、データに合わせて指定します。なお、引用符の中にカンマを含む本格的なCSVはawkでは正しく扱えないため、その場合は専用ツールを使います。

組み込み変数

組み込み変数 $0・NF・NR

・NF・NR

awkには、便利な組み込み変数があります。$0は行全体、NFはその行の列数、NRは現在の行番号です。

$0・NF・NR
# $0: 行全体(2行目だけ表示する例)
awk 'NR == 2 {print $0}' list.txt
# suzuki 25 osaka

# NF: 列の数
echo "a b c d" | awk '{print NF}'     # 4

# NR: 行番号を付けて表示
awk '{print NR": "$1}' list.txt
# 1: tanaka
# 2: suzuki

# 最後の列を取り出す(NF を列番号として使う)
awk '{print $NF}' list.txt

実機でも、NFa b c dに対して4(列数)、NRで各行に1:2:と行番号を付けられ、NR == 2で2行目だけを表示できました。$NFと書くと「NF列目」=最後の列を取り出せるのも便利なテクニックです。列数が行によって違うデータでも、$NFなら常に末尾の列が取れます。

条件で行を絞る(比較・パターン)

awkは、{}の前に条件を書くと、その条件を満たす行だけを処理します。数値の比較も、grepのようなパターンマッチもできます。

条件で絞り込む
# 2列目(年齢)が30以上の行の名前を表示
awk '$2 >= 30 {print $1}' list.txt
# tanaka
# sato

# tokyo を含む行の名前を表示(/パターン/)
awk '/tokyo/ {print $1}' list.txt
# tanaka
# sato

# 条件だけ書くと、一致した行全体が表示される(grep風)
awk '$2 >= 30' list.txt

実機でも、'$2 >= 30 {print $1}'で年齢30以上のtanakasatoだけが表示され、'/tokyo/ {print $1}'でも同じ2人が絞り込めました。grepとの違いは、数値として比較できることです。「2列目が30以上」「3列目が100未満」のような条件はawkの得意分野です。&&(かつ)や||(または)で複数条件も書けます(例: '$2 >= 30 && $3 == "tokyo"')。

合計を集計する(END)

awkのもう1つの強力な機能が集計です。変数に足し込んでいき、ENDブロック(全行の処理が終わったあとに実行される)で結果を表示します。

END で合計を出す
# 商品名,単価,個数 のCSV
cat items.csv
# apple,120,3
# banana,80,5
# cherry,300,2

# 単価×個数の合計金額を集計
awk -F, '{sum += $2 * $3} END {print sum}' items.csv
# 1360

# 行数を数える(wc -l 相当)
awk 'END {print NR}' items.csv

# 平均を出す
awk -F, '{sum += $2} END {print sum / NR}' items.csv
ENDは「全部読み終わったあと」に実行される

実機で確認したところ、awk -F, '{sum += $2 * $3} END {print sum}'は、各行の「単価×個数」をsumに足し込み、最後に合計1360を表示しました(検算: 120×3+80×5+300×2=1360で一致)。{...}の部分は各行ごとに実行され、END {...}は全行を読み終わったあとに1回だけ実行されます。変数は宣言なしで使えて、数値は0から始まるため、sum += $2と書くだけで集計できます。逆に、最初に1回だけ実行したい処理(見出しの表示など)はBEGIN {...}に書けます。ログの件数集計や売上の合計など、「表計算ソフトを開くほどではない集計」がコマンド1行で済むのがawkの魅力です。

printfで整形・パイプとの組み合わせ

出力をきれいにそろえたいときは、printの代わりにprintfを使います。また、awkはパイプで他のコマンドの出力を受け取るのが定番です。

printf とパイプ
# printf で桁をそろえる(%-8s: 左寄せ8文字、%3d: 右寄せ3桁)
awk '{printf "%-8s %3d\n", $1, $2}' list.txt
# tanaka    30
# suzuki    25

# パイプで他コマンドの出力を処理(例: プロセスのPIDだけ)
ps aux | awk '{print $2}'

# df の使用率だけを見る
df -h | awk '{print $5, $6}'

実機でも、printf "%-8s %3d\n"で名前が左寄せ8文字・数値が右寄せ3桁にそろって表示されました。printfの書式は%s(文字列)・%d(整数)・%.2f(小数2桁)などが使えます(末尾の\nは忘れずに)。また、ps aux | awk '{print $2}'のようにパイプでコマンド出力の特定の列だけを抜くのは、Linuxで毎日のように使われるパターンです。grepで行を絞ってからawkで列を抜く、という組み合わせも定番です。

主な書き方一覧

awkでよく使う書き方をまとめます。

書き方 働き
'{print $1}' 1列目を表示
-F, 区切り文字をカンマに(CSV)
$0 / NF / NR 行全体 / 列数 / 行番号
'$2 >= 30 {print}' 条件を満たす行だけ処理
'/パターン/ {print}' パターンに一致する行だけ
'{sum += $2} END {print sum}' 合計の集計
printf "%-8s %3d\n", ... 桁をそろえて整形

よくある失敗

CSVで列が取れない

標準の区切りは空白です。カンマ区切りには-F,を指定します。

プログラム部分をダブルクォートで囲む

"$1"がシェルに展開されて壊れます。シングルクォート'...'で囲みます。

$0と$1を混同する

とを混同する

$0は行全体、$1は1列目です。

ENDを付けずに合計を毎行表示してしまう

{print sum}だけだと各行で表示されます。最後に1回ならEND {print sum}です。

printfで改行を忘れる

printfは自動で改行しません。書式の末尾に\nを付けます。

よくある質問

Qawkで特定の列だけ取り出すには?
Aawk '{print $1}' ファイルで1列目が取り出せます。$2が2列目、$NFが最後の列です。複数の列は'{print $1, $3}'のようにカンマで並べます。標準では空白・タブ区切りとして扱われます。
QCSVファイルの列が取れません。
Aawkの標準の区切りは空白のため、カンマ区切りのCSVはそのままでは分割されません。awk -F, '{print $1}'のように-Fで区切り文字を指定してください。コロン区切りなら-F:、タブなら-F'\t'です。
Qawkとgrep・sedはどう使い分けますか?
A行の検索(含む/含まない)はgrep、文字列の置換はsed、列の抽出・数値の条件・集計はawkが得意です。たとえば「2列目が30以上の行」のような数値条件や、合計・平均の計算はawkにしかできません。組み合わせて使うことも多いです。
Qawkで合計や平均を出すには?
Aawk '{sum += $2} END {print sum}' ファイルで2列目の合計が出せます。{...}は各行で実行され、END {...}は全行を読み終わったあとに1回だけ実行されます。平均はEND {print sum / NR}のように行数NRで割ります。
Q条件に合う行だけ処理するには?
A{}の前に条件を書きます。awk '$2 >= 30 {print $1}'で「2列目が30以上の行の1列目」を表示します。/パターン/で正規表現の一致も指定でき、&&||で複数条件も組み合わせられます。

まとめ

  • 列の抽出はawk '{print $1}'$NFで最後の列も取れます。
  • CSVには-F,で区切り文字を指定します。
  • $0(行全体)・NF(列数)・NR(行番号)が組み込みで使えます。
  • 条件は'$2 >= 30 {...}'のように{}の前に書きます。
  • 集計は'{sum += $2} END {print sum}'ENDは最後に1回実行されます。

awkは、列の抽出から集計まで、1行で済ませられる強力なテキスト処理コマンドです。「区切りが違うときは-F」「集計はEND」の2点を押さえれば、ログの集計やコマンド出力の加工が一気に楽になります。grepsedと組み合わせて、Linuxのテキスト処理を使いこなしましょう。