Quick Start
awk4j
(AWK for Java Platform)
Java (SE 6 以降) のスクリプト・フレームワーク jrunscript コマンドを使用して
AWKスクリプトを実行する。
一般的な AWK コマンドの書式
${AWK} [ options ] -f script-file [ -F fs ] [ -v var=value ]
[--] [ var=value | datafile ... ]
${AWK} [ options ]
"script"
〃
awk4j スクリプト実行コマンドの書式
jrunscript [ options ] -l awk4j[.Java
|.JavaScript ] [ -e "script" | -f script-file ... ] [""]
[ -F fs ] [ -v var=value ] [--] [ var=value | datafile ... ]
マクロ呼び出しの書式
${AWK4J}
[ -e "script" | -f script-file ... ] [""]
[ -F fs ] [ -v var=value ] [--] [ var=value |
datafile ... ]
${AWK4JAVASCRIPT}
〃
主なオプション
-f script-file
AWK
スクリプトをファイル script-file から読み込む
-F fs
--field-separato fs 組み込み変数 FS
(入力フィールドセパレータ) に fs を設定する
-v var=val
--assign var=val
スクリプトを実行する前に、変数 var
に値 val を設定する
-- オプションの終了を意味し、AWKスクリプトに "-"
で始まる引数を与える場合に使用する
スクリプト実行コマンド固有のオプション
-e script
AWKスクリプトを文字列で直接指定する
-Dtranslator.awkcommand=${AWK} トランスレータを
AWKコマンドを使用して実行する
"" 空の文字列を指定してスクリプト実行コマンド (jrunscript)
の引数の終了を明示する
Note: -v の無い var=val
指定はファイル名指定の一部であり、 引数がファイル名としてアクセスされた時点で設定される。
サンプルの実行は GNU make コマンドを使用する。
awk4j-dir
# awk4j を展開(インストール)したディレクトリ
+-- lib #
実行時ライブラリ (awk4j.jar など)
+-- ext #
オプションのホスト言語などを格納する拡張ライブラリ
+-- tmp #
作業用ディレクトリ (ログ出力などに使用する)
+-- sample
# サンプルディレクトリ
+-- bin #
サンプルをコンパイルしたオブジェクトを格納する(サンプル実行時にのみ使用)
+-- src #
サンプルのソース
makefile
# サンプルを実行するための make ファイル
# make コマンドを入力
cd sample
make ターゲット
または
make -C sample ターゲット
make usage
Java スクリプティング環境の確認
Java jrunscript の動作確認をおこなう。 (awk4j の動作には Java SE 6
SDK 環境が必要)
make check
${JRUNSCRIPT} -help # コマンドヘルプを表示
${JRUNSCRIPT} -cp awk4jライブライパス -q
# 組み込まれたエンジン一覧を表示
Language awk, Java 2006.12 implemention "awk4j (AWK for Java Platform)"
Language awk, ECMAScript 2006.12 implemention "awk4j.JavaScript (AWK on
ECMAScript)"
Language ECMAScript 1.6 implemention "Mozilla
Rhino"
スクリプトを実行
Java jrunscript でスクリプトを実行する。
make script
${AWK4J} -e 'BEGIN { print "Hello World!" }' #
AWK.Java エンジンで実行
${AWK4J} -f PrimeNumber.awk 40
${AWK4J} -f PrimeNumber.java 80
${AWK4JAVASCRIPT} -f PrimeNumber.awk 20 #
AWK.JavaScript エンジンで実行
${AWK4JAVASCRIPT} -f PrimeNumber.js 25
世界最短スクリプト(1字)でホームページにアクセス
awk4j の入力ファイルは、 URL
指定が可能であり、 一般ファイルと同じインターフェイスで読み込みが可能。
入力ファイルの文字コードは、 URL の "#" フラグメント部 (参照
reference とも呼ぶ) にて指定する。
(コード指定は省略可)
インターネットにアクセスして RSSニュース を閲覧
RSS(Rich Site Summary; XML) の終了タグ
</?>
を、レコード区切りとして読み込み、タイトルと記事
フィールドを表示する。
make news
# RSS の<title>と<description>を表示
${AWK4J} -e '
BEGIN {
RS="</[^>]+>"}
# 終了タグを設定
{gsub(/\n+/,"")}
# 余分な改行を削除
/
<title>/
{sub(/^.+>/,"\n"); print}
/
<description>/
{gsub(/^.+>|<.+/,""); print}
'
http://feeds.nikkeibp.co.jp/oss#utf-8
パターン検索 (simple grep)
指定されたファイルを検索するためのパターン (ex. shell 変数 RE)
を受け取ってマッチした行を出力する。
make grep
# コマンドライン引数で指定されたパターンを受け取るコードを書く (引数のクリアを忘れずに)
${AWK4J} -e 'BEGIN {re=ARGV[1];
ARGV[1]=""}
$0~re {printf
"%s(%d): %s\n", FILENAME, FNR, $0}' ${RE}
datafiles
# 検索パターン(変数)をスクリプトに埋め込む場合
${AWK4J} -e '/${RE}/
{printf "%s(%d): %s\n", FILENAME, FNR, $0}' datafile
# コマンドライン引数で検索パターンをスクリプト変数に埋め込む (AWK の機能の利用)
${AWK4J} -e '$0~re
{printf "%s(%d): %s\n", FILENAME, FNR, $0}' re=${RE}
datafiles
Tip: コマンドライン引数で変数値を設定するには、 -v
var=value or var=value
オプションを使用する。
単語の出現頻度を調べる
標準入力からデータを読み込み、 出現頻度の高い順から (指定が無い場合は 25)
個を選んで、 標準出力に出現回数と共に降順に出力する。
shellスクリプトで表現すると以下のようになる。 (出展:
O'REILLY~; 詳解
シェルスクリプト; ch5.4)
1) tr -cs
A-Za-z\'
'\n' | # 英単語以外の文字を改行に変換
2) sort |
#
昇順に並び替え
3)
uniq -c |
#
重複を取り除き出現回数をカウント
4)
sort -k1,1nr -k2 |
# 出現回数(降順)、 単語(昇順)で並び替え
5)
sed ${1:-25}q
# この shell
を呼び出したときの引数 $1 で出力件数を指定
make wf
${AWK4J} -e '
{ split($0, T, /[^A-Za-zA-Za-z一-鶴ァ-ヶー]+/); #
英字カナ漢字を単語とする
for
(w in T)
if ("" != T[w]) M[T[w]]++ #
単語の出現回数をカウント
}
END { for (w in M) #
パイプラインに出力してコマンドを実行
print M[w]
"\t" w |("sort -k1,1nr -k2
|sed " ((0<n)?n:25)
"q")
}
' n=10 datafiles
Note: 内部コードは Unicode であり、
正規表現の文字クラスの省略形 [一-鶴ァ-ヶー]
の利用は、 コード体系依存となるため注意が必要!
(Java 正規表現エンジンの仕様は、
"java.util.regex" を参照)
Note: パイプラインに出力してコマンドを実行 (AWK
仕様): print |
"command" により、 上記の例では、 AWK
(print ), sort と sed が別プロセスで並列に実行される。
C 言語ツールを AWKスクリプトに移植 (GNU AWK との互換性)
C 言語で書かれた、 月齢計算 (unix ツール pom.c) を AWKスクリプトに移植。
make pom
# awk4j と GNU AWK でそれぞれ実行
${AWK4J} -f Pom.awk 2006/11/05 21:58:00
${GAWK} -f Pom.awk 2006/11/05 21:58:00
2006/11/05 21:58:00: The Moon was Full # 当然、実行結果は同じ
???
pom
のソースおよびライセンス条件 (BSD) は pom.c
ソース参照
Note: systime(): GNU AWK
拡張関数で、 基準時点 (1970-01-01
00:00:00 UTC,)
からの経過秒数を返す。
Note: strftime([format [,
timestamp]]):
GNU AWK 拡張関数で
ISO C標準ライブラリ仕様。
引数timestamp省略時は現在時刻を使用する。また、 引数formatが省略された場合は、 "%a %b %d
%H:%M:%S %Z %Y"
を使用する。
Note: strftime(format [,
timestamp]):
awk4j は
Java "java.text.SimpleDateFormat" を実装
(GNU AWK とは非互換)。
引数timestamp省略時は現在時刻を使用する。 引数formatの省略は不可。
Tip: strftime 関数の書式指定は非互換であるが、
Java と ISO C
で共通する機能を利用すれば、 上記のサンプルのように同一の結果を返すことは可能である。
awk4j は、 トランスレータを使用して AWKスクリプトをホスト(スクリプト)言語に変換する。
ホスト言語を経由することにより、
ホスト言語が持つフレームワークを利用したマルチリンガル環境でのスクリプティングが可能となる。
awk4j environment
AWK 言語 |
AWK コマンド (gawk,
awk95など) |
ホスト言語 |
Java |
JavaScript (JSE6) |
JavaScript (Rhino) |
JavaFX |
Groovy |
BeanShell |
Python |
トランスレータ |
AWKスクリプトを
ホスト言語に変換するトランスレータ |
インタプリタ |
- |
gij |
jrunscript |
Rhino interpreter |
- |
Groovy interpreter |
BeanShell interpreter |
Jython interpreter |
コンパイラ |
javac, dx |
gcj, javac |
javac |
- |
Rhino compiler |
javafxc |
Groovy compiler |
- |
Jython compiler |
実行環境 |
Android |
GCJ |
Java
(JSE6) |
Note: Android, GCJ, JavaFX, Python
については、それぞれのドキュメントを参照。
トランスレータの書式
トランスレータは、 AWKスクリプトをホスト(スクリプト)言語 (Java, JavaScript,
BeanShell, Groovy)
に変換する。
トランスレータ コマンドの書式
${JAVA} [ java-options ] org.awk4j.translator.TRANSRATOR [
options ] script-file ...
or
${GAWK} [ awk-options ] -f TRANSRATOR.awk
[
options ] script-file ...
マクロ呼び出しの書式
${AWK2JAVA} [ options
] script-file ... # Java トランスレータ
${AWK2JAVASCRIPT}
〃
# JavaScript 〃
${AWK2BEANSHELL}
〃
# BeanShell 〃
${AWK2GROOVY}
〃
# Groovy 〃
script-file
スクリプト名は Javaクラス名として使用するため、英大文字で始まる英数字とする
主なオプション
-hostscript 1
ホストスクリプト埋め込み指定の有効化 (0)
-include include-dir インクルードライブラリのディレクトリ
("../lib/include")
-package package-name 出力パッケージ名 ("") Java, JavaScript, Groovy
で使用
-srcname sorce-name クラス名 ("Script") jrunscript で使用
-d output-dir
スクリプトコード出力ディレクトリ ("")
or
> output-script-file リダイレクトで出力
Note: トランスレータは AWKスクリプトで記述されており
一般的な AWK コマンド
(gawk, awk95) で実行可能。 また、
Java版のトランスレータは、 自分自身(.awk) をトランスレータで変換したもの(.java)。
AWKスクリプトを Java に変換
AWKスクリプトを Java ソースに変換する。 実行性能は一番良い、 バッチ処理ならこれ。
また、 出力コードは POJO (Plain
Old Java Object: 平凡な Java オブジェクト) であり、 他の Java コードとの組み合わせが容易。
make ccjava
${AWK2JAVA} Script.awk > Script.java #
トランスレータで変換
${JAVAC} -d ${CLASSES} Script.java # コンパイルして実行
${JAVA} -cp ${CLASSES} Script
JavaFX Script に変換
AWKスクリプトを JavaFX Script に変換し、
リッチ・インターネット・アプリケーションとして実行する。
(JavaFX サポート)
make
-f makefx sample
JavaScript に変換
AWKスクリプトを JavaScript ソースに変換する。 実行性能は二番目に良い。
内部オブジェクトの管理は独自意方式であるが
Java との親和性は高い。 Java アプリからスクリプト・エンジン・インターフェイス
(JSR 223: Scripting for the Java™ Platform)
にてアクセスすることにより、 スクリプト言語としての特徴が生きる。
make
-f makejs sample
${AWK2JAVASCRIPT} Script.awk > Script.js #
トランスレータで変換
${JAVA} org.mozilla.javascript.tools.shell.Main Script.js
# Rhino インタプリタで実行
${JAVA} org.mozilla.javascript.tools.jsc.Main -d ${CLASSES}
Script.js # Rhino でコンパイルして実行
${JAVA} -cp ${CLASSES} Script
${AWK4JAVASCRIPT} -f Script.awk # awk4j.JavaScript
エンジンで実行
${AWK4JAVASCRIPT} -f Script.js
${JRUNSCRIPT} -f Script.js # Sun のスクリプトシェルで実行
Note: JavaScript (JSE6) は、 Sun
による Mozilla Rhino
バージョン 1.6R2 に基づく実装で、 サイズおよびセキュリティー上の理由からいくつかのコンポーネントが除外されておりランタイムは
Rhino とは別物。トランスレータが出力する JavaScript ソースは共通に利用できる。
BeanShellスクリプトに変換
AWKスクリプトを BeanShell ソースに変換する。 インタプリタ方式のため処理は重いが、
Java
とほとんど同じ文法(1.4相当)であり Java言語をスクリプト感覚で利用できる。 また、 Remote Server Mode,
BshServlet,
BeanShell Desktop など興味深い機能を持つ。
make
-f makebsh sample
${AWK2BEANSHELL} Script.awk > Script.bsh #
トランスレータで変換
${JAVA} bsh.Interpreter Script.bsh # インタプリタで実行
Groovyスクリプトに変換
AWKスクリプトを Groovy ソースに変換する。 Smalltalk, Python および
Ruby
の影響を受けた文法を持つ。スクリプト としての柔軟性は BeanShell より劣るがバイトコードへのコンパイルが可能。
make
-f makegroovy sample
${AWK2GROOVY} Script.awk > Script.groovy #
トランスレータで変換
${GROOVY_HOME}/bin/groovy Script.groovy # インタプリタで実行
${GROOVY_HOME}/bin/groovyc -d ${CLASSES} Script.groovy
# コンパイルして実行
${JAVA} -cp ${CLASSES} Script
Note: groovy で未サポートの、
for (expression; expression; expression) statement
および
do statement while (expression)
文の実行が可能。
Javaスクリプト API の利用 (試験実装)
Javaスクリプト API は、 Java
コードからスクリプトエンジンを使用するための、 スクリプト言語に依存しないフレームワークである。
API の詳細は、 パケージ "javax.script, javax.tools"
(JSR 223: Scripting for the Java™ Platform, JSR 199: Java™ Compiler
API)
を参照。
Note: awk4j は AWKスクリプトから Java
および JavaScript に変換するための API
を実装している。
Note: awk4j は、 内部でトランスレータを呼び出して
Java
コードに変換して実行しておりインタプリタではない。
make api
文字列でスクリプト
private static void case01()
throws
ScriptException {
ScriptEngineManager manager = new
ScriptEngineManager(); // スクリプトマネージャを生成
ScriptEngine engine = manager.getEngineByName("awk4j"); // エンジンを取得
engine.eval("BEGIN{
print \"Hello, World\" }"); // スクリプトを直接指定して実行
}
スクリプトを読み込んで実行
private static void case02()
throws
ScriptException, FileNotFoundException {
ScriptEngine engine = new
ScriptEngineManager().getEngineByName("awk4j");
FileReader
reader = new java.io.FileReader("src/PrimeNumber.awk");
engine.put(ScriptEngine.ARGV,
new String[] { "10" }); // 引数を設定して
engine.eval(reader);
// スクリプトを実行
}
TODO: ScriptEngine.ARGV の部分は JavaScript
に合わせて"argments"
とすべきかもしれない。
スクリプトをコンパイルして実行
private static void case03()
throws
ScriptException {
ScriptEngine engine = new
ScriptEngineManager().getEngineByName("awk4j");
CompiledScript
obj = ((Compilable) engine).compile("BEGIN{ printf ARGV[1]
}"); // コンパイル
engine.put(ScriptEngine.ARGV, new String[] {
"hello," });
obj.eval();
// コンパイル済みのスクリプトを実行
engine.put(ScriptEngine.ARGV, new String[] {
"world!\n" });
obj.eval();
}
Note: awk4j は内部で必ずコンパイルをおこなうため、
eval() と compile()
はコンパイル済みのオブジェクトを返すかどうかの違いである。
スクリプト内の手続き呼び出し
private static void case04()
throws
ScriptException, NoSuchMethodException {
ScriptEngine engine = new
ScriptEngineManager().getEngineByName("awk4j");
Invocable inv
= (Invocable) engine; // 手続き呼び出しインタフェースを取得
CompiledScript
obj = ((Compilable) engine)
.compile("function func1() { return \"func1: Hello!\"
}"
+ "function func2(s) { return \"func2: \" s
}"); // スクリプトをコンパイル
System.out.println(inv.invokeFunction("func1")); //
直前にコンパイルした手続きの呼び出し
System.out.println(inv.invokeFunction("func2",
(Object) new Object[] { "call fron
Function."
}));
// 引数は配列でラップ
System.out.println(inv.invokeMethod(obj, "func2",
(Object) new Object[] { "call fron
Method." }));
// スクリプトオブジェクトを指定して手続き呼び出し
}
Note: AWK 言語の関数は可変引数であり、 関数
function func(a) は、
Java メソド Object
func(Object... args) に変換される。
Runnable インタフェースを実装して Thread で実行
private static void case05()
throws
ScriptException {
ScriptEngine engine = new
ScriptEngineManager().getEngineByName("awk4j");
Invocable inv = (Invocable) engine; //
手続き呼び出しインタフェースを取得
((Compilable) engine).compile("BEGIN { print
\"Hello, from Thread.\" }");
Runnable runner =
inv.getInterface(Runnable.class); // Runnable
インタフェースの実装
Thread th = new Thread(runner);
th.start(); // Thread で実行
try {
th.join(); // 完了の待ち合わせ
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Note: 実は、 awk4j Java版は最初から
Runnable
インタフェースを実装している。上記のインタフェースの実装の部分は、 コンパイル済みオブジェクトのインスタンスを取得する目的で使用している。
(現在の Javaスクリプト API には、 明にインスタンス化するためのインターフェイスは無い)
awk4j エンジンから JavaScript エンジンの世界へ
awk4j JavaScript版では、 2種類のエンジンを使用しており、 awk4j
エンジンは、 トランスレータを呼び出してスクリプトを変換、 JavaScriptエンジンを呼び出して実行する。
private static void case11()
throws
ScriptException, FileNotFoundException {
ScriptEngine
engine = new ScriptEngineManager().getEngineByName("awk4j.JavaScript");
FileReader reader = new
FileReader("src/PrimeNumber.awk");
CompiledScript obj = ((Compilable)
engine).compile(reader); // トランスレータで変換
engine.put("arguments",
new String[] { "20" }); // コマンド行引数を設定
obj.eval(); // JavaScriptエンジンを呼び出して実行
ScriptEngine
jsengine = obj.getEngine(); // これは Java組込みの
JavaScriptエンジン
String str = (String) jsengine.eval("prime(11)");
// ここからはJavaScriptエンジンの世界
System.out.println("11 までの素数:" + str);
Number num = (Number) jsengine.eval("isPrime(7)");
System.out.println("7 は素数?: " + (1 ==
num.intValue()));
}
トランスレータに関する問題
- AWKスクリプトの互換性
- トランスレータの AWK 文法チェックは不十分である (gawk の --lint
オプションを利用した互換性の確認を推奨する)。
- パフォーマンス
- トランスレータは、 Java または AWK で実行可能である。
パフォーマンス上、大差はないためサンプルは Java 環境で実行させる。
- 変数タイプをスコープ内でダイナミックに変更 (配列変数 ←→ スカラ変数)
(Awk2Javaトランスレータ, gawk, awk95)
- ex. A[1] = 2; A = 3; →
良くないコーディングスタイルであり、 スコープ内での変数タイプ変更は禁止する。
スクリプトエンジンに関する問題
- パス指定は -cp と CLASSPATH の両方必要
- -cp はスクリプトマネージャー対してのみ有効、 スクリプトエンジンには CLASSPATH が必要
(jrunscript の仕様?)
awk4j ランタイムに関する問題
- -
Quick Start
- AWK コマンドの書式
- 一般的な AWK コマンドの書式
- awk4j スクリプト実行コマンドの書式
- コマンドラインでスクリプト
- Java スクリプティング環境の確認
- スクリプトを実行
- おもちゃ箱
- 世界最短スクリプト(1字)でホームページにアクセス
- インターネットにアクセスして RSSニュースを閲覧
- パターン検索 (simple grep)
- 単語の出現頻度を調べる
- C 言語ツールを AWKスクリプトに移植
- いろいろなスクリプト言語
- トランスレータの書式
- AWKスクリプトを Java に変換
- JavaFX Script に変換
- JavaScript に変換
- BeanShellスクリプトに変換
- Groovyスクリプトに変換
- Java からスクリプト
- Javaスクリプト API の利用
- 既知の問題