ここでは、_言語_のことをAWK、AWKプログラムを解釈する_実行ファイル_のことを**awkまたはgawk**と呼びます。
AWKプログラムは、パターンとアクションのペアで構成されます。
pattern1 { action1 }
pattern2 { action2 }
...
パターンには、入力と照合する正規表現を指定できます。 真偽値になる任意の式を指定することもできます。
アクションは、1つ以上のAWKコマンドです。 アクションを囲む波括弧は必須です。
パターンの結果が_true_なら、対応するアクションが実行されます。
AWKは入力を一連のレコードとして解析します。 各レコードは、0個以上のフィールドに分割されます。
デフォルトの動作は次のとおりです。
パターンは省略できます。その場合、アクションは_すべての入力レコード_に対して実行されます。
アクションは省略できます。その場合、デフォルトのアクションは現在のレコードを出力することです。
よく使われる特殊なパターンが2つあります。
BEGINは、入力が読み込まれる前に、対応するアクションを実行します。ENDは、すべての入力を読み込んだ後に、対応するアクションを実行します。フィールドは$1、$2、$3のように参照します。
現在のレコードは$0です。
はっきり言っておくと、これらは厳密には「変数」ではありません。
$は、指定したフィールド番号の値を取得する_演算子_と考えることができます。
これについては、後の概念で詳しく見ていきます。
ほかにもよく使われる組み込み変数を紹介します。
RSは入力のレコード区切りです。
前述のとおり、デフォルト値は改行です。FSは入力のフィールド区切りです。これらの変数は、BEGINアクションブロックで設定することが多いです。
これらの変数は、プログラムの実行中にAWKによって自動的に設定されます。
NFは、現在のレコードのフィールド数を保持します。
$NFを使います。NRは、現在のレコード番号を保持します。
NRはそれまでに処理したレコードの総数を保持します。FNRは、現在の入力ファイルにおける現在のレコード番号を保持します。
NR == FNR {action}
これは「累積のレコード番号が、現在のファイルのレコード番号と等しいなら」という意味です。
これが成り立つのは、_最初の入力ファイル_のレコードだけです。AWKは、Cと同じ真偽の考え方を使います。
0は偽です。AWKはテキスト処理言語なので、真偽値は文字列にも拡張されています。
""は偽です。AWKは、Cと同じ真偽の考え方を使います
AWKは1970年代にベル研究所で生まれました。Cが生まれたのと同じ環境です。 CはAWKの構文に大きな影響を与えました。
気をつけたいちょっとした落とし穴
0は偽です。"0"は真です!AWKのデータ型については、後の概念でさらに詳しく見ていきます。
コメントは#で始まり、行の終わりまで続きます。
awkに入力を渡す方法awkは、ファイルまたは標準入力から入力を読み込むことができます。
次のどの方法でも動作します。
awk '/regex/ {print $1}' file1 file2 ...
awk '/regex/ {print $1}' < file
some_command_here | awk '/regex/ {print $1}'
Unix系のシステムでは、/etc/passwdにユーザーに関する情報が含まれています。
各ユーザーは1行ずつ記述され、フィールドはコロンで区切られています。
ユーザー名を一覧表示するには、次のようにします。
awk '
BEGIN { FS = ":" }
{ print $1 }
' /etc/passwd
{print $1}というアクションにはパターンがないので、すべてのレコードに対して実行されることに注目してください。
出力を、ログインシェルとしてbashを使っているユーザーだけに絞りたい場合は、次のようにします。
awk '
BEGIN { FS = ":" }
$7 == "/bin/bash" { print $1 }
' /etc/passwd
ここでは、他の一般的なUnixコマンドと同じ結果を生み出すawkプログラムをいくつか紹介します。
ファイルを表示する
cat file.txt
awk '1' file.txt
ファイル内のパターンを検索する
grep 'foo.*bar' file.txt
awk '/foo.*bar/' file.txt
ファイルの先頭の数行だけを表示する
head -n 20 file.txt
awk '
1
NR == 20 {exit}
' file.txt
ファイル内のテキストを置換する
sed 's/foo/bar/' file.txt
awk '{sub(/foo/, "bar")};1' file.txt
# or more readably
awk '
{
sub(/foo/, "bar")
print
}
' file.txt