AWK による列の抽出

LinuxBeginner
オンラインで実践に進む

はじめに

Linux でログファイル、CSV、設定ファイルなどの構造化されたテキストデータを扱うとき、特定の列の情報だけを抽出したくなることがあります。たとえば、システムファイルからユーザー名だけを取り出したり、Web アクセスログからステータスコードだけを取り出したりする場合です。

この作業に使う主なツールが awk です。

awk は、テキストをレコード(行)とフィールド(列)の集合として扱います。これが、Linux でプレーンテキストが今でも便利に使われている理由の 1 つです。多くの管理用データ形式は目で確認しやすく、コマンドラインツールでも処理しやすい構造になっています。

  • レコードは通常、改行で区切られます。
  • フィールドは通常、空白文字(スペースまたはタブ)で区切られます。

この「レコードとフィールド」という考え方を身につけると、awk を理解しやすくなります。ファイルを単なるテキストとして見るのではなく、直接参照できる構造化された行と列として扱えるようになるためです。

この実験では、awk を使用して次の操作を学びます。

  1. フィールドを選択する:$1、$2 などを使って特定の列を抽出します。
  2. フィールド区切り文字を定義する:-F オプションを使い、スペース以外の文字(コロンやカンマなど)で区切られたデータを処理します。
  3. 最後のフィールドを参照する:$NF を使って、行の末尾にあるフィールドへ動的にアクセスします。

最初のフィールドを抽出する

まず、スペース区切りの単純なファイルを使います。data.txt はすでに用意されています。

内容を表示します。

cat data.txt

出力:

John 25 Engineer
Alice 30 Manager
Bob 22 Intern

awk では、各行が 1 つのレコードで、各単語が 1 つのフィールドです。

  • フィールド 1($1):名前(例:John)
  • フィールド 2($2):年齢(例:25)
  • フィールド 3($3):役割(例:Engineer)

名前(1 列目)だけを抽出するには、$1 を出力するように awk へ指示します。

awk では、$1、$2 などの式が現在のレコード内のフィールドを表します。$0 は現在の行全体を表します。このフィールド表記を使えるため、awk は構造化されたテキストを簡潔に処理できます。

次のコマンドを実行します。

awk '{print $1}' data.txt

出力:

John
Alice
Bob

次に、この出力をファイルへ保存します。

awk '{print $1}' data.txt > output1.txt

新しいファイルの内容を確認します。

cat output1.txt

フィールドの区切り方を理解する

次は、別のファイル形式として /etc/passwd を使います。このファイルにはユーザーアカウント情報が保存されています。

passwd の先頭部分を表示します。

head -n 3 /etc/passwd

出力は、次のようになります。root:x:0:0:root:/root:/bin/bash

スペースがないことに注目してください。代わりに、フィールドはコロン(:)で区切られています。

このファイルにデフォルトの awk コマンドを実行すると、フィールドを正しく分割できません。デフォルトでは、awk はスペースを区切り文字として扱うためです。

実際に試してみます。

awk '{print $1}' /etc/passwd > output2.txt
head -n 3 output2.txt

行全体が表示されることを確認できます。awk はスペースを見つけられなかったため、行全体を 1 つのフィールド($1)として扱ったからです。

この問題を解決するには、カスタムの フィールド区切り文字を指定する必要があります。

実際のテキスト処理では、データ形式を理解しているかどうかが重要です。区切り文字を間違えると、抽出したつもりの列と、awk が認識する列が一致しません。

カスタムフィールド区切り文字(-F)を使う

コロンで区切られたデータをフィールドとして扱うには、-F フラグを使用します。

awk -F: というコマンドは、列の間の区切り文字としてコロンを使うように awk へ指示します。

-F オプションは、出力や処理を行う前に、awk が各行を解析する方法を変更します。行が正しく分割されると、$1 や $7 などのフィールド参照を意味のある形で使えるようになります。

これで、特定のフィールドを抽出できます。/etc/passwd では、次のフィールドが使われています。

  • フィールド 1 はユーザー名です。
  • フィールド 7 はシェルです。

ユーザー名とシェルだけを抽出します。カンマで区切って複数のフィールドを指定すると、複数のフィールドを出力できます。

awk -F: '{print $1, $7}' /etc/passwd > output3.txt

結果を確認します。

head -n 5 output3.txt

出力は、次のようになります。root /bin/bash

awk が行をコロンで正しく分割し、1 番目と 7 番目のフィールドを空白で区切って出力できたことが分かります。

最後のフィールド($NF)を出力する

行に含まれる列数が正確に分からない場合や、行によって列数が異なる場合があります。それでも、必要なデータが常に最後の列にあると分かっていることがあります。

awk には、$NF(Number of Fields、フィールド数)という組み込み変数があります。

  • NF は現在の行に含まれるフィールド数を保持します。
  • $NF は最後のフィールドの値を表します。

この方法を使うと、列番号を固定値として指定する必要がなくなります。絶対的な列番号よりも末尾からの位置が重要な場合、NF と $NF は柔軟に利用できます。

$NF を使って、/etc/passwd の最後の列を抽出します。

awk -F: '{print $NF}' /etc/passwd > output4.txt

出力を確認します。

head -n 5 output4.txt

ファイルの構造が一定であれば、$7 を使った場合と同じく、シェル(例:/bin/bash)が表示されます。$NF は行の末尾を自動的に参照するため、より堅牢な方法になることがよくあります。

まとめ

この実験では、awk を使ってテキストを解析する基本を学びました。

  1. フィールドの抽出($N):$1、$2 などを使って、データの個々の列にアクセスします。
  2. フィールド区切り文字(-F):-F オプションを使って、コロンやカンマなど、異なる区切り文字で区切られたファイルを処理します。
  3. 最後のフィールド($NF):レコードの最後の列へ動的にアクセスします。

これらの方法を使うと、構造化された生のテキストを、さらに処理しやすい整ったデータストリームへ変換できます。