にわか Python 野郎です。 Python の勉強のネタに、 ミラクル・リナックスの某ブログで話題になったコマンドのタイムアウト処理 を timeoutcmd.py として実装してみた。 ちなみに、これが初のスタンドアロンな Python スクリプト。 2007-01-01 更新: タイムアウト発生時にコマンドに送るシグナルを指定できるようにした。
#!/usr/bin/env python
#
Run a command with a timeout checking
Copyright (c) 2006-2007 SATOH Fumiyasu @ OSS Technology Co.
http://www.osstech.co.jp/
#
Date: 2007-01-01, since 2006-12-31
License: GNU General Public License version 2
import getopt
import signal
import re
import sys
import os
import select
def err(format, *argv):
print >>sys.stderr, sys.argv[0] + ":", format % argv
signum_by_name = {}
signame_by_num = {}
for signame in dir(signal):
if signame.startswith("SIG"):
signum = getattr(signal, signame)
if type(signum) == type(1):
signum_by_name[str(signum)] = signum
signum_by_name[signame] = signum
signum_by_name[re.sub("^SIG", "", signame)] = signum
signame_by_num[signum] = signame
Options
======================================================================
codeontimeout = 255
codeonexecerror = 254
codeonforkerror = 253
signumontimeout = signal.SIGTERM
usage = """Usage: %s [OPTIONS] TIMEOUT COMMAND [ARG ...]
Options:
-s, --signal SIGNAL
Send SIGNAL to COMMAND on timeout
-o, --timeout-code=EXITCODE
Exit code on timeout
-e, --exec-error-code=EXITCODE
Exit code on exec failure
-f, --fork-error-code=EXITCODE
Exit code on fork failure
"""
Command-line options
----------------------------------------------------------------------
try:
opts, args = getopt.getopt(sys.argv[1:], 'hs:o:e:f:',
['help', 'signal=', 'timeout-code=', 'exec-error-code=', 'fork-error-code='])
except getopt.error, msg:
err("%s", msg)
sys.exit(1)
for opt, arg in opts:
if opt in ('-h', '--help'):
print usage
sys.exit(0)
if opt in ('-s', '--signal'):
signame = arg.upper()
if not signumbyname.haskey(signame):
err("invalid signal name: %s", signame)
sys.exit(1)
signumontimeout = signumbyname[signame]
if opt in ('-o', '--timeout-code'):
codeontimeout = int(arg)
if opt in ('-e', '--exec-error-code'):
codeonexecerror = int(arg)
if opt in ('-f', '--fork-error-code'):
codeonfork_error = int(arg)
timeout = float(args[0])
command = args[1:]
Main
======================================================================
r, w = os.pipe()
try:
pid = os.fork()
except OSError, e:
err("fork failed: %s", e.strerror)
sys.exit(codeonfork_error)
Child process
----------------------------------------------------------------------
if pid == 0:
os.close(r)
try:
os.execvp(command[0], command)
except OSError, e:
err("exec failed: %s: %s", command[0], e.strerror)
sys.exit(codeonexec_error)
Parent process
----------------------------------------------------------------------
os.close(w)
p = select.poll()
p.register(r, select.POLLIN)
ready = p.poll(timeout * 1000)
if len(ready) == 0:
err("command timed out: %s", command[0])
os.kill(pid, signumontimeout)
pidexited, status = os.waitpid(pid, 0)
sys.exit(codeontimeout)
pidexited, status = os.waitpid(pid, 0)
sys.exit(status >>
Mailman
のハンドラを書いていて、
自然にオブジェクト指向 & 例外処理を書けるのは気持ちいい!
と感じて Python を覚えようかと思ってみたものの、
例えばリストの長さを求めるのに
と書くのは嫌いかも。
同様に
len(list)
とか
int(string)
も嫌だなぁ。
Ruby みたいに str(number)
のように書ける
ほうが好みだな。
list.length
Python は Mailman のハンドラ書きとデバッグ程度の嗜みにしておいて、 ポスト Perl は Ruby にしてみようかしら?




