Linuxでawkコマンドを使用する方法

  • awkは、パターンとアクションのルールを適用することで、他のプログラムからの出力をフィルタリングおよび操作するために使用されます。
  • awkはテキストから特定のフィールドを出力したり、フィールド間の区切り文字を変更したり、組み込み関数を用いてさまざまなアクションを実行したりできます。
  • awkは、作成者のアルフレッド・アホ、ピーター・ワインバーガー、ブライアン・カーニハンにちなんで名付けられました。

Linuxでは、awkはコマンドラインのテキスト操作ダイナモであり、強力なスクリプティング言語でもあります。その最も優れた機能のいくつかを紹介します。

awkの名前の由来

awkコマンドは、1977年にオリジナルバージョンを執筆した3人のイニシャル、アルフレッド・アホ、ピーター・ワインバーガー、ブライアン・カーニハンを使用して名付けられました。この3人は、伝説的なAT&Tベル研究所のUnixの神殿出身です。それ以降多くの人々が貢献したおかげで、awkは進化を続けてきました。

コマンドライン用の完全なスクリプティング言語であり、テキスト操作ツールキットでもあります。この記事を読んで興味が湧いたら、awkとその機能の詳細を確認できます。

awkの用途:ルール、パターン、アクション

awkは、他のプログラムや関数の出力をフィルタリングおよび操作するために使用されます。awkは、パターンとアクションで構成されたルールを含むプログラムで動作します。awkが実行するアクションは、パターンに一致するテキストで実行されます。パターンは中括弧({})で囲まれます。パターンとアクションを合わせてルールを形成します。awkプログラム全体は、シングルクォート(')で囲まれます。

最も単純なタイプのawkプログラムを見てみましょう。パターンがないため、入力されたすべての行のテキストに一致します。つまり、アクションはすべての行で実行されます。whoコマンドの出力に使用します。

whoの標準出力が次のとおりです:

who

その情報をすべて必要とするのではなく、アカウントの名前だけを確認したい場合があります。whoの出力awkにパイプしてから、awkに最初のフィールドのみを出力するように指示できます。

デフォルトで、awkはフィールドを、空白、行頭、または行末で囲まれた文字列とみなします。フィールドはドル記号($)と数字で識別されます。そのため、$1は最初のフィールドを表し、printアクションで最初のフィールドを出力するために使用します。

次のように入力します:

who | awk '{print $1}'

awkは最初のフィールドを出力し、残りの行を破棄します。

好きなだけ多くのフィールドを出力できます。区切り文字としてカンマを追加すると、awkは各フィールド間にスペースを出力します。

次のように入力して、ログインした時刻(フィールド4)も出力します:

who | awk '{print $1,$4}'

特別なフィールド識別子がいくつかあります。これらは、テキストの全行とテキスト行の最後のフィールドを表します:

  • $0:テキストの全行を表します。
  • $1:最初のフィールドを表します。
  • $2:2番目のフィールドを表します。
  • $7:7番目のフィールドを表します。
  • $45:45番目のフィールドを表します。
  • $NF:「フィールドの数」を表し、最後のフィールドを表します。

次のように入力して、デニス・リッチーの短い引用が含まれる小さなテキストファイルを表示します:

cat dennis_ritchie.txt

awkを使用して、引用の最初のフィールド、2番目のフィールド、最後のフィールドを出力します。ターミナルウィンドウで折り返されていますが、これは単一のテキスト行であることに注意してください。

次のコマンドを入力します:

awk '{print $1,$2,$NF}' dennis_ritchie.txt

テキスト行の18番目のフィールドが「simplicity.」であることはわかりませんし、気にしません。わかっているのはそれが最後のフィールドであるということだけであり、$NFを使用してその値を取得できます。ピリオドは、フィールドの本文の別の文字とみなされます。

awk出力に出力フィールド区切り文字を追加する

デフォルトのスペース文字ではなく、特定の文字をフィールド間に印刷するようにawkに指示することもできます。dateコマンドのデフォルト出力は少し特殊であり、時刻がその真ん中に配置されるためです。ただし、次のように入力して、awkを使用して必要なフィールドを抽出できます:

date

date | awk '{print $2,$3,$6}'

OFS(出力フィールド区切り文字)変数を使用して、月、日、年間に区切り文字を配置します。以下ではコマンドを中括弧({})ではなく、シングルクォート(')で囲んでいることに注意してください:

date | awk 'OFS="/" {print$2,$3,$6}'

date | awk 'OFS="-" {print$2,$3,$6}'

BEGINとENDのルール

BEGINルールは、テキスト処理が開始される前に1回実行されます。実際、awkがテキストを読み取る前ですら実行されます。ENDルールは、すべての処理が完了した後に実行されます。複数のBEGINルールとENDルールを設定でき、順に実行されます。

BEGINルールの例では、以前に使用したdennis_ritchie.txtファイルからの引用全体を、その上にタイトルを付けて出力します。

これを行うには、次のコマンドを入力します:

awk 'BEGIN {print "Dennis Ritchie"} {print $0}' dennis_ritchie.txt

BEGINルールには、独自の中括弧({})で囲まれた独自のアクションセットがあることに注意してください。

この同じ手法を、以前に使用したコマンドでwhoからawkに出力をパイプする場合に使用できます。これを行うには、次のように入力します:

who | awk 'BEGIN {print "Active Sessions"} {print $1,$4}'

入力フィールド区切り文字

awkで空白文字を使用してフィールドを区切らないテキストを処理する場合は、テキストでフィールド区切り文字として使用される文字を指定する必要があります。たとえば、/etc/passwdファイルでは、コロン(:)を使用してフィールドを区切っています。

そのファイルと-F(区切り文字列)オプションを使用して、awkにコロン(:)を区切り文字として使用するように指示します。awkにユーザーアカウントの名前とホームフォルダーを出力するように指示するには、次のように入力します:

awk -F: '{print $1,$6}' /etc/passwd

出力には、ユーザーアカウントの名前(またはアプリケーションまたはデーモンの名前)とホームフォルダー(またはアプリケーションの場所)が含まれています。

awkにパターンを追加する

通常のユーザーアカウントのみを対象としている場合、パターンをprintアクションに含めて他のすべてのエントリをフィルタリングできます。ユーザーID番号は1,000以上であるため、その情報に基づいてフィルタを適用できます。

第3フィールド($3)に1,000以上の値が含まれる場合にのみprintアクションを実行するには、次のように入力します:

awk -F: '$3 >= 1000 {print $1,$6}' /etc/passwd

パターンは、関連付けられているアクションの直前に配置する必要があります。

BEGINルールを使用して、小さなレポートにタイトルを付けることができます。タイトル文字列に改行文字を挿入するには、(\n)表記を使用して次のように入力します:

awk -F: 'BEGIN {print "User Accounts\n-------------"} $3 >= 1000 {print $1,$6}' /etc/passwd

パターンは本格的な正規表現であり、awkの素晴らしさの1つです。

マウントされたファイルシステムのUniversally Unique Identifier(UUID)を表示するとします。/etc/fstabファイルで文字列「UUID」の出現を検索すると、その情報が返されるはずです。

コマンドで検索パターン「/UUID/」を使用します:

awk '/UUID/ {print $0}' /etc/fstab

「UUID」のすべての出現を検索し、それらの行を出力します。printアクションがなくても同じ結果が得られたはずです。デフォルトのアクションはテキストの全行を出力するからです。ただし、明確にするために、明示的にすることがよくあります。スクリプトや履歴ファイルを見ると、自分自身の手がかりを残したことを嬉しく思います。

最初に発見された行はコメント行で、「UUID」文字列はその真ん中にありますが、awkはまだそれを発見しました。正規表現を調整して、awkに「UUID」で始まる行のみを処理するように指示できます。これを行うには、行頭トークン(^)を含む次のように入力します:

awk '/^UUID/ {print $0}' /etc/fstab

いいですね!これで、本物のマウント命令だけが表示されます。出力をさらに絞り込むには、次のように入力して、表示を最初のフィールドに制限します:

awk '/^UUID/ {print $1}' /etc/fstab

このマシンに複数のファイルシステムがマウントされていた場合、それらのUUIDのきちんとした表が得られます。

awkの組み込み関数の使用方法

awkには、コマンドラインとスクリプトの両方から独自のプログラムで呼び出して使用できる関数が数多くあります。少し調べれば、非常に有益であることがわかります。

関数を呼び出す一般的な手法を示すために、数値的な関数を見てみましょう。たとえば、次のコマンドは625の平方根を出力します:

awk 'BEGIN { print sqrt(625)}'

このコマンドは、0(ゼロ)と-1(数学定数、円周率になる)の逆正接を出力します:

awk 'BEGIN {print atan2(0, -1)}'

次のコマンドでは、atan2()関数の結果を出力する前に変更します:

awk 'BEGIN {print atan2(0, -1)*100}'

関数は、パラメータとして式を受け入れることができます。たとえば、25の平方根を求める込み入った方法を次に示します:

awk 'BEGIN { print sqrt((2+3)*5)}'

awkスクリプト

コマンドラインが複雑になったり、再び使用したいルーチンを開発したりした場合は、awkコマンドをスクリプトに転送できます。

このスクリプトの例では、次のすべてを実行します:

  • シェルに、スクリプトを実行するために使用する実行可能ファイルを指示します。
  • awkを準備して、FSフィールド区切り文字変数を使用して、コロン(:)で区切られたフィールドを含む入力テキストを読み取ります。
  • OFS出力フィールド区切り文字を使用して、awkに出力を区切るためにコロン(:)を使用するように指示します。
  • カウンターを0(ゼロ)に設定します。
  • 各テキスト行の2番目のフィールドを空白値に設定します(常に「x」なので、表示する必要はありません)。
  • 変更された2番目のフィールドでその行を出力します。
  • カウンターを増やします。
  • カウンターの値を出力します。

スクリプトを以下に示します。

BEGINルールは準備手順を実行し、ENDルールはカウンター値を表示します。中間ルール(名前もパターンもないため、すべての行に一致します)は、2番目のフィールドを変更し、その行を出力し、カウンターを増やします。

スクリプトの最初の行は、シェルにスクリプトを実行するために使用する実行可能ファイル(この例ではawk)を指示します。また、-f(ファイル名)オプションをawkに渡します。これは、処理するテキストがファイルから取得されることを通知します。スクリプトを実行するときにファイル名をスクリプトに渡します。

スクリプトをテキストとして以下に含めたので、切り取って貼り付けることができます:

#!/usr/bin/awk -fBEGIN { # set the input and output field separators FS=":" OFS=":" # zero the accounts counter accounts=0}{ # set field 2 to nothing $2="" # print the entire line print $0 # count another account accounts++}END { # print the results print accounts " accounts.\n"}

これをomit.awkという名前のファイルに保存します。スクリプトを実行可能にするには、chmodを使用して次のように入力します:

chmod +x omit.awk

これで、スクリプトを実行して/etc/passwdファイルをスクリプトに渡します。これは、スクリプト内のルールを使用して、awkが処理するファイルです:

./omit.awk /etc/passwd

ファイルが処理され、各行が以下に示すように表示されます。

2番目のフィールドの「x」エントリは削除されましたが、フィールド区切り文字は残っていることに注意してください。行がカウントされ、合計が出力の一番下に示されます。

awkはAwkwardの略ではない

awkは、Awkwardの略ではなく、エレガンスの略です。処理フィルターやレポートライターとして説明されています。より正確に言えば、それらの両方、あるいはむしろその両方のタスクに使用できるツールです。awkは、ほんの数行で、従来の言語で広範囲にわたるコーディングを必要とするものを実現します。 その力は、処理するテキストを選択するパターンと、処理を定義するアクションを含むルールという単純な概念によって制御されます。