awk でなんちゃって執事 (多機能版)

「Rubyでなんちゃって執事・改」がPerlで多機能に生まれ変わった件(多謝)にインスパイヤーされて作ってみました。機能は同じレベルだと思います。

先に動かしてみますが、ここではあまり使用例の少ない gawk のライブラリのひとつである getopt.awk を使ってみます。ライブラリを include するには gawk ではなく igawk を用います。

$ igawk -f todo_2.awk
予定無いっすね。暇っすね。

$ igawk -f todo_2.awk -w
ぼっちゃま、本日のご予定を伺ってもよろしいでしょうか?

  ※予定は一行ずつ入力してください。
  ※入力が終了したら「exit」と入力してください。
  ※入力情報は本日の予定に「上書き」されます。

12:05 ボスとランチ
18:30 サンタが迎えにくる
20:00 飲み会 ××集合
21:30 再配達受け取り
exit

復唱します。
12:05 ボスとランチ
18:30 サンタが迎えにくる
20:00 飲み会 ××集合
21:30 再配達受け取り
で、よろしいですね?ご予定承りました。

$ igawk -f todo_2.awk
「12:05 ボスとランチ」とのことですが、ぼっちゃま、寝ないでください、ぼっちゃま。
「18:30 サンタが迎えにくる」と書いてあります。いかがなされますか?
「20:00 飲み会 ××集合」とのことですが、本日はお忙しいでしょうか?
「21:30 再配達受け取り」とのことですが、本日はお忙しいでしょうか?

こんな感じでいいのでしょうか。 コードは以下のようになります。

#! /usr/bin/gawk -f

# getopt.awk ライブラリをロードする
@include getopt.awk

BEGIN {
    # メッセージ (複数記述可能)
    message[1] = "と書いてあります。いかがなされますか?";
    message[2] = "とのことですが、本日はお忙しいでしょうか?";
    message[3] = "とのことです。お忘れではない? それは失礼いたしました。";
    message[4] = "とのことですが、ぼっちゃま、寝ないでください、ぼっちゃま。";

    # 乱数の初期化
    srand();
    # ToDo ファイルの設定
    todo_file = strftime("%Y%m%d") ".txt";

    # getopt.awk からのオプションの取得
    while ((option = getopt(ARGC, ARGV, "w")) != -1) {
        if (option == "w") {
            init_flag = 1;
        }
    }

    # 今日の ToDo ファイルがない場合
    if (getline < todo_file <= 0 && init_flag == 0) {
        print "予定無いっすね。暇っすね。";
        exit 0;
    }

    # 書き込みオプションが設定されている場合
    if (init_flag == 1) {
        close(todo_file);
        print "ぼっちゃま、本日のご予定を伺ってもよろしいでしょうか?";
        print "";
        print "  ※予定は一行ずつ入力してください。";
        print "  ※入力が終了したら「exit」と入力してください。";
        print "  ※入力情報は本日の予定に「上書き」されます。";
        print "";
        while (1) {
            getline input < "/dev/stdin";
            if (input == "exit") {
                break;
            }
            print input >> todo_file;
        }
        close(todo_file);
        print "";
        print "復唱します。";
        while (getline < todo_file > 0) {
            print $0;
        }
        close(todo_file);
        print "で、よろしいですね?ご予定承りました。";
        exit 0;
    }

    # 今日の ToDo ファイルがあって書き込みオプションが指定されていない場合
    if (getline < todo_file > 0 && init_flag == 0) {
        close(todo_file);
        while (getline < todo_file > 0) {
            print "「" $0 "」" message[int(rand() * length(message) + 1)];
        }
        close(todo_file);
        exit 0;
    }
}

少し分かりやすくするために冗長に書いているところもありますので、何をしているか大体分かると思います。 一見便利そうな igawk ですが、igawk 自体が gawk を呼び出す shell script ですので shell script の制限を受けてしまい巨大なスクリプトを動作させることはできません。

また、ファイルの有無を getline で調べている関係上、何度も close() しなければいけないのが awk の欠点でしょうか。