Linux の awk コマンド:テキスト処理

LinuxLinuxBeginner
今すぐ練習

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

AWKを使ったテキスト処理の世界へようこそ。この実験では、システム管理者やデータアナリストにとって一般的なタスクであるログファイルの分析に awk コマンドをどのように使用するかを学びます。AWKはLinuxにおける構造化されたテキストデータの処理に強力なツールで、効率的に情報を抽出、フィルタリング、変換することができます。

あなたがサーバーログを分析して潜在的なセキュリティ脅威やパフォーマンス問題を特定することを任された初級システム管理者だと想像してみてください。このタスクのための主なツールは awk コマンドで、大きなログファイルを迅速に篩り分けて、意味のある洞察を抽出することができます。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL linux(("Linux")) -.-> linux/TextProcessingGroup(["Text Processing"]) linux(("Linux")) -.-> linux/BasicFileOperationsGroup(["Basic File Operations"]) linux/BasicFileOperationsGroup -.-> linux/touch("File Creating/Updating") linux/BasicFileOperationsGroup -.-> linux/cat("File Concatenating") linux/BasicFileOperationsGroup -.-> linux/head("File Beginning Display") linux/TextProcessingGroup -.-> linux/grep("Pattern Searching") linux/TextProcessingGroup -.-> linux/awk("Text Processing") linux/TextProcessingGroup -.-> linux/sort("Text Sorting") linux/TextProcessingGroup -.-> linux/uniq("Duplicate Filtering") subgraph Lab Skills linux/touch -.-> lab-388493{{"Linux の awk コマンド:テキスト処理"}} linux/cat -.-> lab-388493{{"Linux の awk コマンド:テキスト処理"}} linux/head -.-> lab-388493{{"Linux の awk コマンド:テキスト処理"}} linux/grep -.-> lab-388493{{"Linux の awk コマンド:テキスト処理"}} linux/awk -.-> lab-388493{{"Linux の awk コマンド:テキスト処理"}} linux/sort -.-> lab-388493{{"Linux の awk コマンド:テキスト処理"}} linux/uniq -.-> lab-388493{{"Linux の awk コマンド:テキスト処理"}} end

ログファイルの調査

まずは、サンプルログファイルの内容を調査しましょう。このファイルには、この実験全体を通じて分析する疑似サーバーアクセスログが含まれています。

まず、プロジェクトディレクトリに移動しましょう。

cd ~/project

次に、ログファイルの最初の数行を表示しましょう。

head -n 5 server_logs.txt

以下のような出力が表示されるはずです。

2023-08-01 08:15:23 192.168.1.100 GET /index.html 200
2023-08-01 08:16:45 192.168.1.101 GET /about.html 200
2023-08-01 08:17:30 192.168.1.102 POST /login.php 302
2023-08-01 08:18:12 192.168.1.103 GET /products.html 404
2023-08-01 08:19:05 192.168.1.104 GET /services.html 200

このログファイルには、日付と時刻、IPアドレス、HTTPメソッド、要求されたリソース、およびステータスコードを含むサーバー要求に関する情報が含まれています。

基本的なAWKの使い方 - 特定のフィールドの出力

ログファイルの構造を見てきたので、AWKを使って特定の情報を抽出しましょう。デフォルトでは、AWKは各行を空白を基準にフィールドに分割します。これらのフィールドを参照するには $1$2 などを使います。ここで $1 は最初のフィールド、$2 は2番目のフィールド、といった具合です。

ログファイルからIPアドレス(3番目のフィールド)を抽出しましょう。

awk '{print $3}' server_logs.txt | head -n 5

以下のような出力が表示されるはずです。

192.168.1.100
192.168.1.101
192.168.1.102
192.168.1.103
192.168.1.104

このコマンドでは:

  • awk '{print $3}' は、各行の3番目のフィールドを出力するようにAWKに指示しています。
  • 出力を head -n 5 にパイプで送ることで(|)、最初の5行までの表示を制限しています。

次に、IPアドレスと要求されたリソースの両方を出力しましょう。

awk '{print $3, $5}' server_logs.txt | head -n 5

出力:

192.168.1.100 /index.html
192.168.1.101 /about.html
192.168.1.102 /login.php
192.168.1.103 /products.html
192.168.1.104 /services.html

ここでは、各行の3番目のフィールド(IPアドレス)と5番目のフィールド(要求されたリソース)を出力しています。

ログエントリのフィルタリング

AWKの強みの1つは、条件に基づいてデータをフィルタリングする能力です。この機能を使って、ログファイル内のすべてのPOSTリクエストを見つけてみましょう。POSTリクエストはGETリクエストよりもセキュリティ上のリスクが高い可能性があります。

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

awk '$4 == "POST" {print $0}' server_logs.txt

このコマンドの構文を分解して、AWKのフィルタリングがどのように機能するかを理解しましょう:

  1. $4 == "POST" - これは、AWKが各行に対して評価するパターンまたは条件です:

    • $4 は、現在の行の4番目のフィールドを参照します(このログファイルでは、これがHTTPメソッドです)
    • == は、2つの値が等しいかどうかをチェックする等価演算子です
    • "POST" は、比較対象の文字列です
  2. {print $0} - これは、条件が真の場合にAWKが実行するアクションです:

    • 中括弧 {} はアクションを囲みます
    • print は、テキストを出力するコマンドです
    • $0 は、現在の全行(すべてのフィールド)を表します

このコマンドの構造は、AWKのパターン 条件 {アクション} に従っています。AWKは各行を読み取り、条件が真と評価されるとアクションを実行します。条件が指定されていない場合(前の例のように)、すべての行に対してアクションが実行されます。

次のような出力が表示されるはずです:

2023-08-01 08:17:30 192.168.1.102 POST /login.php 302
2023-08-01 09:23:45 192.168.1.110 POST /submit_form.php 200
2023-08-01 10:45:12 192.168.1.115 POST /upload.php 500

次に、ステータスコードが404(Not Found)となったすべてのリクエストを見つけてみましょう:

awk '$6 == "404" {print $1, $2, $5}' server_logs.txt

このコマンドは同じパターンに従っていますが、値が異なります:

  • 条件 $6 == "404" は、6番目のフィールド(ステータスコード)が404に等しいかどうかをチェックします
  • アクション {print $1, $2, $5} は、特定のフィールドのみを出力します:
    • $1 - 1番目のフィールド(日付)
    • $2 - 2番目のフィールド(時刻)
    • $5 - 5番目のフィールド(要求されたリソース)

このような選択的な出力により、必要な情報に集中することができます。

出力:

2023-08-01 08:18:12 /products.html
2023-08-01 09:30:18 /nonexistent.html
2023-08-01 11:05:30 /missing_page.html

論理演算子を使用して、複数の条件を組み合わせることができます:

  • && はAND(両方の条件が真でなければならない)
  • || はOR(少なくとも1つの条件が真でなければならない)
  • ! はNOT(条件を否定する)

たとえば、エラー(ステータスコード >= 400)となったすべてのPOSTリクエストを見つけるには:

awk '$4 == "POST" && $6 >= 400 {print $0}' server_logs.txt

これらのフィルタを使用すると、サーバーログ内の潜在的な問題や疑わしい活動をすばやく特定することができます。

データのカウントと集計

AWK は、出現回数のカウントやデータの集計に非常に優れています。ここでは、各 HTTP ステータスコードのリクエスト数をカウントするために AWK を使用します。

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

awk '{count[$6]++} END {for (code in count) print code, count[code]}' server_logs.txt | sort -n

このコマンドは少し複雑なので、ステップバイステップで解説します:

  1. {count[$6]++} - 各行に対して実行される主要なアクションです:

    • count は、作成する配列(連想配列または辞書)です。
    • [$6] は、6 番目のフィールド(ステータスコード)の値を配列のインデックス/キーとして使用します。
    • ++ はインクリメント演算子で、現在の値に 1 を加えます。
    • つまり、各行に対して、見つかった特定のステータスコードのカウンターをインクリメントします。
  2. END {for (code in count) print code, count[code]} - すべての行を処理した後に実行されます:

    • END は、入力の終わりに一致する特殊なパターンです。
    • {...} は、すべての入力が処理された後に実行するアクションを含みます。
    • for (code in count) は、count 配列のすべてのキーを反復処理するループです。
    • print code, count[code] は、各ステータスコードとそのカウントを出力します。
  3. | sort -n - 出力を sort コマンドにパイプし、数値的にソートします。

AWK が count[$6]++ のような配列を処理するとき、自動的に以下のことが行われます:

  • 配列が存在しない場合は作成します。
  • キーが存在しない場合は、値が 0 の新しい要素を作成します。
  • その後、値を 1 増やします。

次のような出力が表示されるはずです:

200 3562
301 45
302 78
304 112
400 23
403 8
404 89
500 15

この集計結果を見ることで、ログファイル内のステータスコードの分布をすぐに把握できます。

次に、最も頻繁にアクセスされた上位 5 つのリソースを見つけましょう:

awk '{count[$5]++} END {for (resource in count) print count[resource], resource}' server_logs.txt | sort -rn | head -n 5

このコマンドは、いくつかの変更点を除いて似たパターンに従っています:

  1. {count[$5]++} - 5 番目のフィールド(要求されたリソース)の出現回数をカウントします。
  2. END {for (resource in count) print count[resource], resource} - すべての行を処理した後:
    • まずカウントを出力し、その後にリソースを出力します。
    • この順序の変更により、カウントで数値的にソートすることが容易になります。
  3. | sort -rn - 数値的に逆順にソートします(カウントが最も多いものから始まります)。
  4. | head -n 5 - 出力を最初の 5 行(上位 5 つの結果)に制限します。

出力結果:

1823 /index.html
956 /about.html
743 /products.html
512 /services.html
298 /contact.html

これらの AWK コマンドは、配列を使用したカウントと集計の強力さを示しています。このパターンを適用して、データ内の任意のフィールドまたはフィールドの組み合わせをカウントすることができます。

たとえば、IP アドレスごとのリクエスト数をカウントするには:

awk '{count[$3]++} END {for (ip in count) print ip, count[ip]}' server_logs.txt

メソッドとステータスの両方でリクエストをカウントするには:

awk '{key=$4"-"$6; count[key]++} END {for (k in count) print k, count[k]}' server_logs.txt

これらの集計結果を利用することで、トラフィックパターンを理解し、サーバー上の人気のある(または問題のある)リソースを特定することができます。

シンプルなレポートの作成

最後のタスクとして、ログファイルからいくつかの重要な情報をまとめたシンプルな HTML レポートを作成しましょう。このより複雑な操作には、別のファイルに保存された AWK スクリプトを使用します。

まず、以下の内容で log_report.awk という名前のファイルを作成します。

ヒント: 以下の内容をコピーしてターミナルに貼り付けると、ファイルを作成できます。

cat << 'EOF' > log_report.awk
BEGIN {
    print "<html><body>"
    print "<h1>Server Log Summary</h1>"
    total = 0
    errors = 0
}

{
    total++
    if ($6 >= 400) errors++
    ip_count[$3]++
    resource_count[$5]++
}

END {
    print "<p>Total requests: " total "</p>"
    print "<p>Error rate: " (errors/total) * 100 "%</p>"
    
    print "<h2>Top 5 IP Addresses</h2>"
    print "<ul>"
    for (ip in ip_count) {
        top_ips[ip] = ip_count[ip]
    }
    n = asort(top_ips, sorted_ips, "@val_num_desc")
    for (i = 1; i <= 5 && i <= n; i++) {
        for (ip in ip_count) {
            if (ip_count[ip] == sorted_ips[i]) {
                print "<li>" ip ": " ip_count[ip] " requests</li>"
                break
            }
        }
    }
    print "</ul>"
    
    print "<h2>Top 5 Requested Resources</h2>"
    print "<ul>"
    for (resource in resource_count) {
        top_resources[resource] = resource_count[resource]
    }
    n = asort(top_resources, sorted_resources, "@val_num_desc")
    for (i = 1; i <= 5 && i <= n; i++) {
        for (resource in resource_count) {
            if (resource_count[resource] == sorted_resources[i]) {
                print "<li>" resource ": " resource_count[resource] " requests</li>"
                break
            }
        }
    }
    print "</ul>"
    
    print "</body></html>"
}
EOF

この AWK スクリプトをセクションごとに理解しましょう。

  1. BEGIN ブロック: 入力行を処理する前に実行されます

    BEGIN {
        print "<html><body>"  ## HTML構造の開始
        print "<h1>Server Log Summary</h1>"
        total = 0  ## 総リクエスト数のカウンタを初期化
        errors = 0  ## エラーリクエスト数のカウンタを初期化
    }
  2. メイン処理ブロック: 入力ファイルの各行に対して実行されます

    {
        total++  ## 総リクエスト数のカウンタをインクリメント
        if ($6 >= 400) errors++  ## エラーレスポンス(ステータスコード >= 400)をカウント
        ip_count[$3]++  ## IPアドレス(フィールド3)ごとのリクエスト数をカウント
        resource_count[$5]++  ## リソース(フィールド5)ごとのリクエスト数をカウント
    }
  3. END ブロック: すべての入力行を処理した後に実行されます

    END {
        ## 要約統計情報を出力
        print "<p>Total requests: " total "</p>"
        print "<p>Error rate: " (errors/total) * 100 "%</p>"
    
        ## 上位5つのIPアドレスを処理して出力
        #...
    
        ## 上位5つのリクエストされたリソースを処理して出力
        #...
    
        print "</body></html>"  ## HTML構造の終了
    }

上位の IP アドレスのソートロジックを見てみましょう(リソースのセクションも同じように動作します)。

## カウントをソート用の新しい配列にコピー
for (ip in ip_count) {
    top_ips[ip] = ip_count[ip]
}

## 配列を値の降順でソート
n = asort(top_ips, sorted_ips, "@val_num_desc")

## 上位5つのエントリを出力
for (i = 1; i <= 5 && i <= n; i++) {
    ## このカウントに一致する元のIPを見つける
    for (ip in ip_count) {
        if (ip_count[ip] == sorted_ips[i]) {
            print "<li>" ip ": " ip_count[ip] " requests</li>"
            break
        }
    }
}

このスクリプトでは:

  • asort() 関数が配列をソートします
  • "@val_num_desc" は、値を数値的に降順でソートするように指示する特別な引数です
  • ネストされたループが上位5つのエントリを見つけて出力します

では、AWK スクリプトを実行してレポートを生成しましょう。

awk -f log_report.awk server_logs.txt > log_report.html

-f オプションは、AWK に指定されたファイルからスクリプトを読み込むように指示します。

  • -f log_report.awk - log_report.awk ファイルから AWK スクリプトを読み込みます
  • server_logs.txt - このファイルをスクリプトで処理します
  • > log_report.html - 出力を log_report.html ファイルにリダイレクトします

cat コマンドを使用してレポートの内容を表示できます。

cat log_report.html

このレポートは、総リクエスト数、エラー率、上位5つの IP アドレス、および上位5つのリクエストされたリソースの要約を提供します。実際のシナリオでは、この HTML ファイルをウェブブラウザで開いて整形された表示を見ることができます。

このスクリプトで使用したアプローチは、AWK がより複雑なデータ分析タスクにどのように使用できるかを示しています。特定のニーズに基づいて、このスクリプトを拡張して追加の統計情報や異なる視覚化を含めることができます。

まとめ

おめでとうございます!AWKコマンドを使ったログ分析のこの実験を完了しました。学んだことを振り返りましょう。

  1. 基本的なAWKの使い方:構造化されたテキストファイルから特定のフィールドを出力する。
  2. データのフィルタリング:AWKの条件を使って特定のログエントリを選択する。
  3. カウントと要約:AWKを使ってログデータから統計を生成する。
  4. レポートの作成:フォーマットされたレポートを生成するために、より複雑なAWKスクリプトを書く。

これらのスキルは、システム管理者やデータアナリストとしてのあなたの将来の仕事で、ログファイルの分析、データの処理、レポートの作成にとても役立ちます。

この実験では扱わなかった追加のAWKパラメータと機能をいくつか紹介します。

  • -F:空白以外のフィールド区切り文字を指定する。
  • -v:変数に値を割り当てる。
  • NR:現在のレコード番号を表す組み込み変数。
  • NF:現在のレコードのフィールド数を表す組み込み変数。
  • BEGINEND ブロック:初期化と終了処理用の特殊なパターン。
  • 組み込み関数:数学関数、文字列関数など。

覚えておいてください、練習こそがAWKをマスターする鍵です。この実験のコマンドやスクリプトを変更して、ログファイルのさまざまな側面を分析したり、他の種類の構造化されたテキストデータを処理したりしてみてください。

参考資料