はじめに
awk でオプション解析を行いたかったのでシェルの getopts
相当の機能を持つ関数を実装しました。ロングオプションなどには対応していません。gawk だけではなく POSIX に準拠したどの awk の実装でも動作します。
awk 版 getopts の実装
getopts
という関数名にしていますが、シェルの getopts
コマンド互換のインターフェースにするつもりはありません。
function getopts(optstring, args, i, j) {
i = OPTIND ? int(OPTIND) : (OPTIND = 1)
j = int(substr(OPTIND, length(i) + 2))
OPTERR = OPTARG = ""
if (!(i in args)) return 0
if (args[i] == "--") { OPTIND = i + 1; return 0 }
if (args[i] !~ /^-./) return 0
OPT = substr(args[i], j + 2, 1)
OPTARG = substr(args[i], j + 3)
if (index(optstring, OPT ":")) {
if (OPTARG == "") {
if (!(++i in args)) {
OPTERR = "option requires an argument -- " OPT
OPTARG = ":"
return 0
}
OPTARG = args[i]
}
OPTIND = i + 1
} else if (OPT != ":" && index(optstring, OPT)) {
OPTIND = (OPTARG == "") ? (i + 1) : (i "," (j + 1))
} else {
OPTERR = "illegal option -- " OPT
OPTARG = "?"
return 0
}
return 1
}
使い方
上記の関数を awk スクリプトの冒頭に埋め込んだりして実行してください。以下はシェルスクリプトに埋め込んだ場合のサンプルコードです。
#!/bin/sh
${AWK:-awk} "$(cat getopts.awk)"'
BEGIN {
while(getopts("fgo:p:", ARGV)) {
if (OPT == "f") print OPT
if (OPT == "g") print OPT
if (OPT == "o") print OPT " : " OPTARG
if (OPT == "p") print OPT " : " OPTARG
}
if (OPTERR) {
printf "%s (OPT: %s, OPTARG: %s)\n", OPTERR, OPT, OPTARG
exit 1
}
print "Arguments:"
for (i = OPTIND; i < ARGC; i++) {
print ARGV[i]
}
}' "$@"
以下のグローバル変数を使用します。
-
OPTIND
次にオプションを解析する引数位置- 新しいオプション解析を始める時は1に設定すること
-
OPT
読み込んだオプション -
OPTARG
オプション引数(存在する場合) -
OPTERR
エラー時のメッセージ
getopts
はオプション解析の終了またはエラー時に偽を返します。エラー時には OPTRERR
にエラーメッセージを OPTARG
にエラーの種別を設定します。
-
OPTARG
エラーの種別-
?
不正なオプション -
:
オプション引数が必要な場面で、オプション引数が存在しない場合
-
その他の実装
gawk でも getopt.awk という同等の処理を行う関数が Public Domain で提供されています。こちらはロングオプションにも対応しているようです。
ロングオプション対応を除いて機能的には大差ないのですが、少々使い方やコードが冗長に感じたので再実装しています。
さいごに
このコードのライセンスは今のところ特に指定していませんが自由に使用してください。リポジトリを以下にあります。