ページ

2017年12月13日水曜日

scriptコマンドをpythonで

Python 3.4.3 のマニュアル http://docs.python.jp/3.4/library/pty.html にあるサンプルからの習作。NetBSDにならって -r と -p でタイムスタンプの記録と再生に対応させた。

なお、Linux の util-linux 由来の script コマンドは、`-t` オプションで間隔は記録してくれるけれど、タイムスタンプが残らない。

script.py:
#!/usr/bin/python
import argparse
import os
import pty
import sys
import time
import struct
from signal import signal, SIGCHLD

parser = argparse.ArgumentParser()
parser.add_argument('-a', dest='append', action='store_true')
parser.add_argument('-p', dest='playback', action='store_true')
parser.add_argument('-r', dest='rawout', action='store_true', default=False)
parser.add_argument('filename', nargs='?', default='typescript')
options = parser.parse_args()

shell = os.environ.get('SHELL', 'sh')
rawout = options.rawout
filename = options.filename
mode = 'ab' if options.append else 'wb'

def playback(filename):
    mode = os.O_RDONLY
    fd = os.open(filename, mode)
    stamp = os.read(fd, 24)
    while stamp:
 buf_len, sec, usec, direction = struct.unpack("QQII", stamp)
        tso = sec + usec/1000000.0
 direction = chr(direction)
 if direction == 's':
     print "Script started on %s" % time.asctime(time.localtime(sec))
            tsi = tso
     buf = os.read(fd, buf_len)
 elif direction == 'e':
     print "\nScript done on %s" % time.asctime(time.localtime(sec))
     buf = os.read(fd, buf_len)
 elif direction == 'i':
     buf = os.read(fd, buf_len)
 elif direction == 'o':
            t = tso - tsi
     time.sleep(t)
            tsi = tso
     buf = os.read(fd, buf_len)
     os.write(1, buf)
        stamp = os.read(fd, 24)
    os.close(fd)
    sys.exit(0)

def record(fd, buf, direction):
    sec, usec = [int(x) for x in ('%f' % time.time()).split('.')]
    stamp = struct.pack("QQII", len(buf), sec, usec, ord(direction))
    fd.write(stamp)
    fd.write(buf)

if (options.playback):
    playback(filename)

with open(filename, mode) as script:
    def read(fd):
        data = os.read(fd, 1024)
        if (rawout):
            record(script, data, 'o')
        else:
            script.write(data)
        return data

    def finish(signum, frame):
        pid, e = os.wait()

    print 'Script started, file is %s' % filename
    if (rawout):
        record(script, '', 's')
    else:
        script.write(('Script started on %s\n' % time.asctime()).encode())

    signal(SIGCHLD, finish)
    pty.spawn(shell, read)

    if (rawout):
 record(script, '', 'e')
    else:
 script.write(('Script done on %s\n' % time.asctime()).encode())
    print 'Script done, file is %s' % filename

0 件のコメント:

コメントを投稿