Linuxでテキストを操作するためのAWK言語の使い方
紹介
Linuxユーティリティは、しばしばUnixの設計哲学に従います。ツールは小型であることが奨励され、入力と出力にはプレーンテキストファイルを使用し、モジュール方式で動作します。このようなレガシーのおかげで、sedやawkのようなツールを使用した優れたテキスト処理機能があります。
awkは、プログラミング言語であり、テキストデータを非常に便利な方法で操作するために使用できるテキスト処理ツールです。このガイドでは、awkコマンドラインツールの使い方と、テキストを処理するための方法を探ります。
基本構文
現代のすべてのLinuxシステムにはデフォルトでawkコマンドが含まれているため、使用を開始するためにインストールする必要はありません。
awkは、予測可能な形式でフォーマットされたテキストファイルを扱うときに最も便利です。たとえば、表形式データの解析や操作に優れています。行ごとに処理を行い、ファイル全体を反復します。
デフォルトでは、フィールドを区切るために空白(スペース、タブなど)を使用します。幸運なことに、あなたのLinuxシステム上の多くの設定ファイルはこの形式を使用しています。
awk コマンドの基本的な形式は次のとおりです:
- awk '/search_pattern/ { action_to_take_on_matches; another_action; }' file_to_parse
任意のawkコマンドから検索部分またはアクション部分のいずれかを省略できます。デフォルトでは、「アクション」部分が指定されていない場合に実行されるアクションは「print」です。これは単に一致するすべての行を印刷します。
検索部分が指定されていない場合、awkは各行に対してリストされたアクションを実行します。
両方が指定されている場合、awk は検索部分を使用して現在の行がパターンに一致するかどうかを判断し、一致した場合にはアクションを実行します。
最も簡単な形では、catのようにawkを使用して、テキストファイルのすべての行を画面に表示することができます。
友達のグループの好きな食べ物をリストしたfavorite_food.txtファイルを作成してください。
- echo "carrot sandy
- wasabi luke
- sandwich brian
- salad ryan
- spaghetti jessica" > favorite_food.txt
今、awk コマンドを使用してファイルを画面に印刷します:
- awk '{print}' favorite_food.txt
画面にファイルが印刷されます:
carrot sandy
wasabi luke
sandwich brian
salad ryan
spaghetti jessica
これはあまり役に立ちません。ファイル内の「sand」というテキストを検索することで、awkの検索フィルタリング機能を試してみましょう:
- awk '/sand/' favorite_food.txt
carrot sandy
sandwich brian
ご覧のように、awkは今や「sand」という文字を含む行のみを印刷します。
正規表現を使用すると、テキストの特定の部分をターゲットにできます。文字列「sand」で始まる行のみを表示するには、正規表現^sandを使用します:
- awk '/^sand/' favorite_food.txt
今回は、1行だけが表示されます:
sandwich brian
同様に、アクションセクションを使用して、印刷したい情報の部分を指定できます。たとえば、最初の列だけを印刷するには、次のコマンドを使用します:
- awk '/^sand/ {print $1;}' favorite_food.txt
sandwich
各列(空白で区切られた)をその列番号に関連付けられた変数で参照できます。例えば、最初の列は $1、二番目は $2 で、全行を $0 で参照することができます。
内部変数と拡張フォーマット
awkコマンドは、ファイルを処理する際に特定の情報の断片を割り当てるためにいくつかの内部変数を使用します。
awkが使用する内部変数は次のとおりです:
- ファイル名: 現在の入力ファイルを参照します。
- FNR:現在の入力ファイルに対する現在のレコードの番号を参照します。例えば、2つの入力ファイルがある場合、これは各ファイルのレコード番号を合計ではなく示します。
- FS: レコード内の各フィールドを表すために使用される現在のフィールド区切り文字。デフォルトでは、これは空白に設定されています。
- NF: 現在のレコードにおけるフィールドの数.
- NR: 現在のレコードの番号。
- OFS: 出力データのフィールドセパレーターです。デフォルトでは、これは空白に設定されています。
- ORS: 出力データのレコードセパレーターです。デフォルトでは、これは改行文字です。
- RS: 入力ファイル内の異なるレコードを区別するために使用されるレコードセパレーター。デフォルトでは、これは改行文字です。
これらの変数の値は、ファイルのニーズに合わせて自由に変更できます。通常、これは処理の初期化フェーズ中に行います。
これで別の重要な概念に入ります。awkの構文は、これまで使用してきたものよりもやや複雑です。また、ファイル処理の前後にそれぞれ実行するコマンドを含むことができるオプションのBEGINおよびENDブロックもあります。
これにより、私たちの拡張構文は次のようになります:
- awk 'BEGIN { action; }
- /search/ { action; }
- END { action; }' input_file
BEGIN と END のキーワードは、検索パラメータのように特定の条件のセットです。これらは文書が処理される前と後で一致します。
これは、BEGINセクションの内部変数のいくつかを変更できることを意味します。例えば、/etc/passwdファイルは、空白ではなくコロン(:)で区切られています。
このファイルの最初の列を印刷するには、次のコマンドを実行してください:
- awk 'BEGIN { FS=":"; }
- { print $1; }' /etc/passwd
root
daemon
bin
sys
sync
games
man
. . .
情報を印刷するために、BEGINとENDブロックを使用できます。次のコマンドを使用して、ファイルのデータをタブで整然とスペースをあけてテーブルに変換します。使用する際は\tを使います:
- awk 'BEGIN { FS=":"; print "User\t\tUID\t\tGID\t\tHome\t\tShell\n--------------"; }
- {print $1,"\t\t",$3,"\t\t",$4,"\t\t",$6,"\t\t",$7;}
- END { print "---------\nFile Complete" }' /etc/passwd
この出力が表示されます:
User UID GID Home Shell
--------------
root 0 0 /root /bin/bash
daemon 1 1 /usr/sbin /bin/sh
bin 2 2 /bin /bin/sh
sys 3 3 /dev /bin/sh
sync 4 65534 /bin /bin/sync
. . .
---------
File Complete
ご覧のように、awkの機能を活用することで、物事をかなりうまくフォーマットできます。
拡張された各セクションは任意です。実際、別のセクションが定義されている場合、主要なアクションセクション自体も任意です。例えば、以下のようなことができます:
- awk 'BEGIN { print "We can use awk like the echo command"; }'
そして、この出力が表示されます:
We can use awk like the echo command
では、出力のフィールド内でテキストを検索する方法を見てみましょう。
フィールド検索と複合表現
以前の例の一つで、あなたはfavorite_food.txtファイルの中で「sand」で始まる行を印刷しました。これは、行全体の始まりを探していたので簡単でした。
フィールドの先頭で検索パターンが一致するかどうかを調べたい場合はどうすればよいですか?
各人の食べ物の前にアイテム番号を追加したfavorite_food.txtファイルの新しいバージョンを作成してください:
- echo "1 carrot sandy
- 2 wasabi luke
- 3 sandwich brian
- 4 salad ryan
- 5 spaghetti jessica" > favorite_food.txt
このファイルから「sa」で始まるすべての食品を見つけたい場合は、次のように試してみることから始めると良いでしょう:
- awk '/sa/' favorite_food.txt
これは「sa」を含むすべての行を示しています:
1 carrot sandy
2 wasabi luke
3 sandwich brian
4 salad ryan
ここでは、単語の中で「sa」というインスタンスをすべて一致させています。これにより「わさび」のように真ん中にパターンがあるものや、「サンディ」のように欲しい列にはないものも含まれます。この場合、あなたが興味を持っているのは、第二列で「sa」で始まる単語だけです。
このコマンドを使用すると、awk に第二列の先頭のみを一致させるように指示できます:
- awk '$2 ~ /^sa/' favorite_food.txt
ご覧のように、これにより私たちは2列目の先頭でのみ一致を検索することができます。
この field_num ~ 部分は、awk が2番目の列のみを注視するよう指定しています。
3 sandwich brian
4 salad ryan
波形 (~) の前に「!」文字を含めることで、一致しないものを簡単に検索できます。このコマンドは、「sa」で始まる食べ物が含まれていないすべての行を返します。
- awk '$2 !~ /^sa/' favorite_food.txt
1 carrot sandy
2 wasabi luke
5 spaghetti jessica
もし後で「sa」で始まらない行だけに興味があることと、アイテム番号が5未満であることを決めたら、このような複合表現を使用できます:
- awk '$2 !~ /^sa/ && $1 < 5' favorite_food.txt
これにより、いくつかの新しい概念が紹介されます。最初の概念は、&&演算子を使用して、行が一致するための追加の要件を追加する能力です。これを使用すると、一致するための任意の数の条件を組み合わせることができます。この場合、最初の列の値が5未満であることをチェックするために、この演算子を使用しています。
この出力が表示されます:
1 carrot sandy
2 wasabi luke
awkを使用してファイルを処理できますが、他のプログラムの出力を使用することもできます。
他のプログラムからの出力処理
他のプログラムの出力を解析するために、ファイル名を指定する代わりにawkコマンドを使用できます。例えば、ipコマンドからIPv4アドレスを解析するためにawkを使用することができます。
ip a コマンドは、あなたのマシン上のすべてのネットワークインターフェースに関するIPアドレス、ブロードキャストアドレス、その他の情報を表示します。eth0 と呼ばれるインターフェースの情報を表示するには、次のコマンドを使用します:
- ip a s eth0
次の結果が表示されます:
2571: eth0@if2572: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:0b brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.11/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
awkを使用してinet行をターゲットにし、IPアドレスだけを出力することができます:
- ip a s eth0 | awk -F '[\/ ]+' '/inet / {print $3}'
-F フラグは awk に対して、正規表現 [\/ ]+ を使用してスラッシュやスペースで区切ることを指示します。これにより、行 inet 172.17.0.11/16 が別々のフィールドに分割されます。IPアドレスは三番目のフィールドにあり、行の始まりのスペースもフィールドとしてカウントされるためです。これは、スラッシュだけでなくスペースでも区切っているためです。この場合、awk は連続したスペースを単一のスペースとして扱ったことに注意してください。
出力にはIPアドレスが表示されます:
172.17.0.11
awkを使用して他のコマンドの出力を検索または解析できる多くの場所が見つかるでしょう。
結論
今の時点で、awk コマンドを使用してテキストファイルやテキストストリームを操作、形式設定、選択的に印刷する方法についての基本的な理解が得られているはずです。ただし、Awkはもっと大きなトピックであり、実際には変数の割り当て、制御構造、組み込み関数などを備えた完全なプログラミング言語です。信頼性の高い方法でテキストを形式設定するために、自分のスクリプト内で使用することができます。
awk についてもっと知りたい場合は、その開発者による無料のパブリックドメインの本を読むと、より詳しい情報を得ることができます。
