シェルコマンドラインでもっとうるさい sleep であればええやんけ

一つ前のを投稿し終えてすぐに気付いた。

もっとうるさければいいじゃんね:

okcancel_or_timeout_dialog.py
 1 #! py -3
 2 # -*- coding: utf-8 -*-
 3 from __future__ import unicode_literals
 4 
 5 
 6 import sys
 7 import re
 8 import time
 9 
10 
11 try:
12     import Tkinter as tkinter  # python 2.x, but sorry, I'm not testing it.
13     from tkSimpleDialog import Dialog
14 except ImportError:
15     import tkinter
16     from tkinter.simpledialog import Dialog
17 
18 
19 class OkCancelTimeout(Dialog):
20     def __init__(self, parent, title, elapse, timeout_is_cancel):
21         self._title = title
22         self._arrivetime = time.time() + elapse
23         self._timeout_is_cancel = timeout_is_cancel
24         self.excode = 1  # for sys.exit(1)
25         Dialog.__init__(self, parent, "settings")
26 
27     def body(self, master):
28         self._master = master
29         tit = tkinter.Label(master, text=self._title)
30         tit.pack()
31         self._cdtxt = tkinter.StringVar()
32         self._cdtxt.set("{:+.3f}".format(time.time() - self._arrivetime))
33         cdt = tkinter.Label(master, textvariable=self._cdtxt)
34         cdt.pack()
35         self._master.after(100, self._timerfun)
36 
37     def _timerfun(self, *args):
38         now = time.time()
39         self._cdtxt.set("{:+.3f}".format(now - self._arrivetime))
40         if now < self._arrivetime:
41             self._master.after(100, self._timerfun)
42         else:
43             if not self._timeout_is_cancel:
44                 self.ok()
45             else:
46                 self.cancel()
47 
48     def apply(self):
49         self.excode = 0
50 
51 
52 if __name__ == '__main__':
53     import argparse
54     ap = argparse.ArgumentParser()
55     ap.add_argument(
56         "elapse", nargs="?",
57         default="1",
58         help="NUMBER[SUFFIX]: SUFFIX may be `s' for seconds (the default), \
59 `m' for minutes, `h' for hours or `d' for days.  Unlike most implementations \
60 that require NUMBER be an integer, here NUMBER may be an arbitrary floating \
61 point number.")
62     ap.add_argument("--title", default="Please wait...")
63     ap.add_argument(
64         "--timeout_is_cancel", action="store_true")
65     args = ap.parse_args()
66     elapse = args.elapse.strip()
67     m = re.match(r"^([\d.eE+-]+)([mhd]){0,1}$", elapse)
68     if not m:
69         ap.error("invalid elapse")
70     v = float(m.group(1))
71     s = m.group(2)
72     elapse = (v * {"m": 60, "h": 60*60, "d": 60*60*24, None: 1}[s])
73     root = tkinter.Tk()
74     root.withdraw()
75     dlg = OkCancelTimeout(root, args.title, elapse, args.timeout_is_cancel)
76     sys.exit(dlg.excode)

まったく同じものを書いた人は相当多いんではないかと予想する。初心者向けのお題にちょうどよさげよねこれ。

少しだけスクリプトが長くなったので、動かさずに振る舞いを想像するのがやや難しくなったかもしんないけど、GUI になっただけであって「お待て、時間を」のためのものであるゴールの部分は変わってなくて、「Ctrl-c の誘惑、もしくは陰謀」から逃れてることが違う。「キッチンタイマー」ちうキーワードですぐにこの発想に至るべきよね、なんでインタラプトにこだわってたんだか。

てわけで、さっきの例だと:

1 [me@host: ~]$ # 別の bash セッションで、以下「hogemannder」コマンドが入力とする「viiideo.mkv」を
2 [me@host: ~]$ # 作っていて、あと2分くらいで出来そうだ、と見込みを立てている状態で...
3 [me@host: ~]$ okcancel_or_timeout_dialog.py $((60*2)) && hogemannder.exe viiideo.mkv -out=viiideo_converted.mp4

「想定より早く viiideo.mkv が出来たぜ」の際にはタイムアウトを待たずに OK を、「viiideo.mkv 作成に失敗しやがったぁ」なら cancel を、そしてこの素晴らしい世界に祝福を。


2021-04-18追記:
結構日常的に使うので、少し拡張した上で gist 管理にした:

これも取り込んでるが、まぁフォントサイズを調整したことの方が個人的には大きいかもな。小さすぎて読めなかったんだわ。