ウェブサイト検索

Linux awkコマンドのテキストフィルタリングの6つの使い方


ジャンプリンク

  • 正規表現を使用してテキストを一致させる
  • 行番号、長さ、フィールド数、または最後のフィールドで行を選択
  • 数値フィールドの値を比較してフィルターする
  • 一致するパターン間の行の範囲をキャプチャする
  • 不要または重複したエントリを除外する
  • 特定の列を選択してテキストを再フォーマットする

awkコマンドは、Linuxにおける多用途なテキスト処理ツールです。パターン、条件、およびアクションを使用してファイルをフィルタリングおよび操作します。さまざまなシナリオに対応しており、ログ、設定ファイル、または任意のテキストファイルから特定のデータを簡単に抽出できます。

ここでは、awkでテキストをフィルタリングする一般的な方法をいくつか紹介します。これには、正規表現検索、行やフィールドの選択、数値によるフィルタリングなどが含まれます。

正規表現を使用してテキストを一致させる

正規表現は習得が非常に難しいことで知られていますが、テキスト操作における万能ツールです。awkのようなツールと組み合わせて使用すれば、単純なパターンから複雑なパターンまで、ファイル全体をミリ秒単位で検索することができます。

基本的な構文から始めましょう。

awk '/pattern/ {print}' filename`

スラッシュは awk に対して正規表現を使用していることを示し、中括弧は一致した際に実行する操作を含みます。例えば、次のようにしてログファイル中の「error」を含むすべてのログエントリを表示できます。

awk '/error/ {print}' syslog.log

その一行コマンドは "error" という単語を含むすべての行を取得しますが、正規表現を使えばさらに高度な検索が可能です。例えば、INFO または WARN で始まる行を見つけるには、次のコマンドを使用します:

awk '/^(INFO|WARN)/ {print}' syslog.log

ここで、パイプ記号 | は OR 演算子として機能し、キャレット ^は行の先頭にマッチします。

私が正規表現について好きな点は、正確な単語にとどまらず、ワイルドカードを使ってより複雑な検索ができることです。例えば、次のパターンを使えば、テキストファイル内のメールアドレスを見つけることができます:

awk '/[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]+/ {print}' contacts.txt

このパターンは、文字と数字の連続に続いて @ 記号、その後にさらに文字と数字、ドット、そして最後に再び文字が続くシーケンスに一致します。すべてのメール形式に完全に対応しているわけではありませんが、一般的なもののほとんどはキャッチできます。

特定のフィールド内でより正確に一致させるために、チルダ演算子(~)を使用することもできます。この方法は構造化データに対して非常に効果的です。例えば、各行の3番目のフィールドだけでERRORを検索したい場合は、次のように使用できます:

awk '$3 ~ /ERROR/ {print}' system.log

このアプローチにより、行全体を検索するよりも精度が高くなります。さらに、大文字と小文字を区別する必要がある場合は、次のように tolower() 関数を使用してください:

awk 'tolower($0) ~ /error/ {print}' mixed_case.log

このコマンドは検索前に各行を小文字に変換するため、ERROR、Error、error、その他の大文字小文字の組み合わせも検出できます。

行番号、長さ、フィールド数、または最後のフィールドで行を選択

時には、内容ではなく行の位置や特性に基づいて特定の行が必要な場合があります。awk は、行を位置や構造でフィルタリングする組み込み変数を使って、これらのシナリオを美しく処理します。これらの組み込み変数には、NR、length()、NF、および $NF が含まれます。

まずは NR 変数から始めましょう。これは Record の数(または単に行番号)を表します。awk は読み込む各行ごとにこれを増加させます。これを使って特定の行や範囲を取得することができます。

ファイルの最初の10行を表示するには、次のコマンドを使用します:

awk 'NR <=10 {print}' largefile.txt
    

同様に、すべての偶数行を取得するには、2を使用します。

awk 'NR % 2 == 0 {print}' file.txt
    

範囲の場合、複数の NR 条件を && 演算子で組み合わせることができます。例えば次のように:

awk 'NR >= 50 && NR <= 100 {print}' file.txt
    

これは50行目から100行目までを出力します。ファイルのフォーマットが不規則な場合や、空行を除外したい場合には、awkとlength()関数を組み合わせて使用することもできます。

例えば、length() 関数で文字数を数え、その後 80 文字を超える行だけを表示するには、次のようにします:

awk 'length($0) > 80 {print}' code.py
    

さて、次にもう一つよく使われる変数、NFについて説明しましょう。これはフィールド数を指します。この変数を使うと、awkは各行をデリミタ(デフォルトではスペースやタブ)に基づいて自動的にフィールドに分割します。

例えば、CSVファイルや構造化データの場合、NF変数を使ってフィールド(列)の数を数えることができます。各行が含むフィールドの数に基づいてフィルタリングすることも可能です:

awk 'NF == 5 {print}' customer_data.csv

これは、正確に5つのフィールドを持つ行だけを保持し、不完全なレコードを見つけるのに役立ちます。逆に、正確に5つのフィールドを持たない行だけを表示したい場合は、== の代わりに != 演算子を使用してください。さらに、少なくとも5つのフィールド(列)を持つ行を表示するには、>= 演算子を使用します。

NFはフィールドの数を教えてくれますが、$NFは最後のフィールドの値を教えてくれます。$NF変数は、フィールドの数に関係なく、各行の最後のフィールドを表します。列の数が変動するファイルを扱う際には、非常に便利です。

この指示を実行してください:

awk '$NF == "COMPLETED" {print}' task_list.txt

これは、一部の行が3つのフィールドを持ち、他の行が7つのフィールドを持っていても、COMPLETEDで終わるすべての行を見つけます。

これらの条件をすべて組み合わせることもできます:

awk 'length($0) > 50 && NF >= 4 {print}' mixed_data.txt

このコマンドは、50文字より長く、かつ少なくとも4つのフィールドを含む行のみを表示します。短い行や不完全な行は出力に含まれないようにします。

数値フィールドの値を比較してフィルターする

awkは、数値を含むフィールドを単なるテキストではなく実際の数値として扱うのに十分賢いため、特別な変換関数を使わなくても数学的な比較を行うことができます。これにより、まったく新しいフィルタリングの可能性が広がります。

さて、学生のスコアが入ったCSVがあり、80点以上の学生だけを返したいとします。これを実現するには、次のようにします:

awk -F, '$2 > 80 {print $1, $2}' scores.csv

ここでは、awk にフィールドがカンマで区切られていることを伝えるために -F を使用します。$2 は二番目のフィールドまたは列(スコア)を指し、$1 は名前を指します。

テキストファイルを扱う際、フィールドに % 記号が含まれているとパーセンテージが問題を引き起こすことがあります。gsub() を使ってそれを取り除くことができます:

awk '{gsub(/%/, "", $4); if($4 > 75) print}' performance.txt

このコマンドは4番目のフィールドから%記号を削除し、残った数値が75を超えているかどうかを確認します。

論理演算子を使って複数の条件を組み合わせることもできます。例えば、CSVファイルから500ドルから2000ドルの間の売上値を抽出したい場合は、次のように実行します:

awk -F, '$3 > 500 && $3 < 2000 {print}' sales.csv
    

条件は ||(OR)演算子で組み合わせることもできます。例えば、売上が非常に高いか非常に低いレコードを見つけたい場合は、次のように使用します。

awk -F, '$3 > 5000 || $3 < 100 {print}' sales.csv
    

数値の比較を超えて、特定のテキストに一致させたり、日付を確認したり、不要なレコードを除外したりするために、複数の条件を使用することもできます。

「&&」と「||」を組み合わせることもできます。ただし、論理を正しく制御するには丸括弧が不可欠です。例えば、残高が1000ドルを超える場合に限り、ステータスがACTIVEまたはPENDINGであるアカウントを見つけたいとします。その場合、次のように書きます:

awk -F, '($2 == "ACTIVE" || $2 == "PENDING") && $3 > 1000' accounts.csv

かっこなしでは、演算子の優先順位がフィルターの意味を変えてしまいます。

一致するパターン間の行の範囲をキャプチャする

ほとんどのLinuxユーザーは、特定の情報を取得するためにgrepを使用することに慣れています。しかし、awkもまた、start_patternに一致する行から始まり、end_patternに一致する行で終わる行の範囲を選択することができます。

構文は非常にシンプルで洗練されています。

awk '/start_pattern/,/end_pattern/' filename

これは開始行、中間のすべての行、および終了行をキャプチャします。マーカー自体を除外したい場合は、次のようにフラグベースの方法を使用できます:

awk '/BEGIN/{flag=1; next} /END/{flag=0} flag' logfile.txt

さらに、指定したテキストで始まり、次の空行で終わる完全なエラーブロックをキャプチャすることもできます。

awk '/ERROR:/,/^$/ {print}' application.log

ここで、awk は「ERROR:」を含む行を見つけた時に行の出力を開始し、最初の空行を見つけるまで出力を続けます。

不要または重複したエントリを除外する

データのクリーニングは、不要なものを取り除くことを意味することが多いです。awk は、ノイズを除去し、冗長なデータを削除するための簡単な方法を提供します。

NOT 演算子 (!) は除外のための主なツールです。任意のパターンや条件の前に配置することで、一致を反転させ、一致しないすべての行に対して awk がアクションを実行するように指示できます。

例えば、アプリケーションのログファイルからDEBUGを含むすべてのメッセージを除外したい場合は、次のようにします。

awk '!/DEBUG/' application.log

このコマンドは、application.log の各行を出力します。ただし、行に DEBUG という単語が含まれている場合は除きます。

これをフィールドベースの条件と組み合わせることもできます。例えば、内部監視用のIPアドレスから来なかったすべてのトラフィックを表示することができます。

awk '$1 != "10.0.0.5"' access.log

同様に、awkのもう一つの便利な操作は、設定ファイルからコメント(#で始まる行)や空行を取り除くことです。これを行うには、次のようにします:

awk '!/^#/ && NF > 0 {print}' config.ini

これは、#で始まる行をスキップし、空行も削除します。

特定のフィールドに基づいて重複を削除することもできます。例えば、ID、Name、Email の3つの列がある contact_list CSV ファイルがあるとします。各ユニークなメールアドレス(3列目)について最初のレコードだけを保持するには、次のようにします:

awk '!seen[$3]++ {print}' contact_list.csv

さらに、tolower() 関数を使用して大文字と小文字を区別しない除外を行うこともできます。

特定の列を選択してテキストを再フォーマットする

生データはしばしば実際には必要ない構造で提供されますが、awkを使うとそれをより有用な形に簡単に並べ替えることができます。特定の列を選択したり、順序を変更したり、さらには新しいフィールドに結合することさえ可能です。

例えば、ファイルから2列目と5列目だけを出力したい場合は、次のように使用できます。

awk -F, '{print $2, $5}' sales.csv

列の順序を変更したい場合は、$5 と $2 を入れ替えてください。

デフォルトでは、awk は出力をスペースで区切りますが、パイプ記号など自分の区切り文字を挿入することもできます。

awk '{print $1 "|" $3}' data.txt

CSVファイルを扱うとき、最初の行はしばしばヘッダーです。NR > 1を使ってスキップし、列を並べ替えてメールのあとに名前を表示することができます。

awk -F, 'NR > 1 {print $3, "->", $1, $2}' contacts.csv

フィールドを組み合わせて新しいフィールドを作成することもできます。例えば、メールを印刷する前に、名前と姓を結合してフルネームにすることなどです。

awk -F, '{print $1 " " $2, $3}' contacts.csv

最後に、出力をより見やすくしたい場合は、BEGINブロックを使ってデータの前に独自のヘッダーを追加することができます。

awk 'BEGIN {print "Name,Email"} {print $1 "," $2}' data.txt

これらの簡単な例だけで、テキストを自分のニーズに合った形式に再フォーマットし始めることができます。


覚えておいてください。awkは構造化されたテキスト、つまり一貫したパターンやフィールド区切りのあるデータを処理するのに優れています。データ形式が規則的であるほど、awkの威力は増します。そして、これらのフィルタリング技術を他のLinuxツールとパイプで組み合わせると、非常に効率的なテキスト処理ワークフローを作り出すことができます。