awkのコマンドライン

タグ: awk   gawk  

gawk(GNU Awk)の解説記事をいくつか書きます。最初はコマンドラインの説明です。

本当は公式ドキュメントを翻訳しようと考えたのですが、ライセンスを精査するのが面倒、量が多すぎる、公式のやり方で貢献しようとすると手順が複雑なため、今回は個人レベルのまとめ記事にします。

今回はコマンドラインからの起動についてです。

注意点

昔のawkは日本語などのマルチバイトをサポートしていませんでした。そこで、ローカルに対応したコードや実行形式ファイルが配布されていました。

そうしたバージョンではいろいろな名前がついていました。主に、gの代わりに別のアルファベットが利用されていました。

ネット上の情報には、こうした古い時代のawkについて書かれたものがあります。参考にする時に、注意しましょう。

Unicode全盛の近年では、現在のバージョンのgawkはUnicodeをサポートしています。

最新のLinuxディストリビューションのawkは、gawkが採用されていることが多いのですが、軽量化が必須のDockerイメージなどでは、GNUではないawkが採用されていることがあります。その場合、日本語を含むデータを処理しようとすると、正しく扱えません。

この程度の知識を持っていれば、ネット情報に従っても動かない場合に、焦らずに済むでしょう。

GNU Awkの確認方法

大抵のLinux系でawkコマンドは、gawkのことが多いのですが、全部ではありません。これ以降の記事はgawkについての記事です。

そこでまずは、使用しているawkがgawkであるかどうかを確認しましょう。

$ awk -h
...
Examples:
    gawk '{ sum += $1 }; END { print sum }' file
    gawk -F: '{ print $1 }' /etc/passwd

例のコマンドがgawkになっていれば、awkで実行されているのはgawkです。

もしくは:

$ awk --version
GNU Awk 4.1.3, API: 1.1
Copyright (C) 1989, 1991-2015 Free Software Foundation.

awkgawkでない場合でも、gawkをリポジトリなどからインストールすると、自動的に置き換わるディストリビューションが多いかと思います。

もし、置き換わらないディストリビューションを利用している場合は、awkの代わりに、gawkを直接呼び出してください。

私はタイプ量を少し減らすため、記事中はawkとタイプします。

なお、バージョン表示で出力されている通り、バージョンは4.1.3で内容を確認しています。

コマンド形式とオプション

基本の実行形式は、以下の2つです。

awk [オプション] -f プログラムファイル [--] 入力データファイル …
awk [オプション] [--] 'スクリプト' 入力データファイル …

最初の形式は、スクリプトをテキストファイルに用意し、実行する形式です。2つ目は俗に言う「一行野郎」で、スクリプトをコマンドラインで直接書いてしまう形式です。--はLinuxのコマンドラインツールでよく使用される、オプションの終わりを示す印です。例えば入力データファイル名の先頭が-で始まっている場合、そのまま指定するとオプションとして処理されるため、明示的にオプションの終わりを示す方法が用意されています。

オプションにはいろいろありますが、使用頻度の高いものを上げると以下の通りです。

  • -F フィールドセパレータ フィールドを分離する文字を指定します。
  • -f プログラムファイル 実行するスクリプトを指定します。
  • -v 変数=値 実行するスクリプトへ渡す変数とその値を指定します。
  • -e 'スクリプト' 明示的にスクリプトを示す

すべてのコマンドラインについては、英語の公式ドキュメントを参照するか、awk -hで確認できます。

複数のawkスクリプト

2つほど、知っておくと便利なポイントを説明します。私自身、これを知っていれば楽にスクリプト書けたのにというポイントです。内容の詳細については、以降に投稿する記事を参照してください。

複数のawkスクリプトをコマンドラインで一度に指定できます。

1.awk

BEGIN { print "Enter 1 BEGIN." }
{ print "Handle lines at 1." }
END { print "Enter 1 END." }

2.awk

BEGIN { print "Enter 2 BEGIN." }
{ print "Handle lines at 2." }
END { print "Enter 2 END." }

data.txt

データーの1行目
データーの2行目

上記のファイルを用意し、次のように実行できます。

$ awk -f 1.awk -f 2.awk data.txt
Enter 1 BEGIN.
Enter 2 BEGIN.
Handle lines at 1.
Handle lines at 2.
Handle lines at 1.
Handle lines at 2.
Enter 1 END.
Enter 2 END.

スクリプトの順番を入れ替えてみましょう。

$ awk -f 2.awk -f 1.awk data.txt
Enter 2 BEGIN.
Enter 1 BEGIN.
Handle lines at 2.
Handle lines at 1.
Handle lines at 2.
Handle lines at 1.
Enter 2 END.
Enter 1 END.

BEGIN、END、全入力行で実行されるコードが、-fオプションで指定された順番で実行されます。

コマンドラインでの引数の指定

スクリプト内の変数値をコマンドラインで指定可能です。

1.awk

BEGIN { print "aaa:", aaa, "(1.awkのBEGIN)" }
{ print "aaa:", aaa, "(1.awk)" }

スクリプトの内容は、変数aaaの内容を表示するものです。

data.txt

データーの1行目
データーの2行目

まずは、変数値を指定せずに実行してみます。

$ awk -f 1.awk data.txt data.txt
aaa:  (1.awkのBEGIN)
aaa:  (1.awk)
aaa:  (1.awk)
aaa:  (1.awk)
aaa:  (1.awk)

data.txtを2回読み込んでいます。

awkでは未定義の変数を出力すると空文字列になります。エラーにはなりません。

変数値を指定する方法は2つあります。まずはデータファイル指定の前で指定する方法です。

$ awk -f 1.awk aaa=2222222 data.txt aaa=3333333 data.txt
aaa:  (1.awkのBEGIN)
aaa: 2222222 (1.awk)
aaa: 2222222 (1.awk)
aaa: 3333333 (1.awk)
aaa: 3333333 (1.awk)

データファイル指定の前で指定した場合は、データファイルを読み込む時点で値が設定されるため、BEGINの中ではまだ未定義です。

BEGINの中で変数の値を調べる必要がある場合は、-vオプションを使用し、値を指定します。

$ awk -v aaa=1111111 -f 1.awk data.txt data.txt
aaa: 1111111 (1.awkのBEGIN)
aaa: 1111111 (1.awk)
aaa: 1111111 (1.awk)
aaa: 1111111 (1.awk)
aaa: 1111111 (1.awk)

-vオプションで指定した変数値は、入力ファイルの指定前の変数値指定で上書きされます。

$ awk -v aaa=1111111 -f 1.awk aaa=2222222 data.txt aaa=3333333 data.txt
aaa: 1111111 (1.awkのBEGIN)
aaa: 2222222 (1.awk)
aaa: 2222222 (1.awk)
aaa: 3333333 (1.awk)
aaa: 3333333 (1.awk)