#! /usr/bin/env python import subprocess import difflib import time import sys import os import os.path import optparse def changed_lines(oldlines, newlines): markers = { 'replace': ' ', 'insert': '+', 'delete': '-' } if oldlines is None: markers['insert'] = ' ' oldlines = [] sm = difflib.SequenceMatcher(None, oldlines, newlines) for (type, ostart, oend, nstart, nend) in sm.get_opcodes(): if type == 'replace': for i in xrange(nstart, nend): yield markers[type], i, newlines[i] elif type == 'insert': for i in xrange(nstart, nend): yield markers[type], i, newlines[i] elif type == 'delete': for i in xrange(ostart, oend): yield markers[type], i, oldlines[i] else: pass return def main(argv): op = optparse.OptionParser( usage="%prog [options] command...", description=("Run a command at regular intervals and show the lines" " that have changed between each run, with a timestamp")) op.add_option("-i", "--interval", type='float', default=10.0, help="Seconds between each command run [%default]") op.add_option("-f", "--timeformat", type='string', default="%H:%M:%S", help="strftime style format string for timestamp [%default]") op.add_option("-s", "--separator", type='string', default=" %c ", help="separator between timestamp and line [\"%default\"]") op.disable_interspersed_args() try: (opts, command) = op.parse_args(argv[1:]) except SystemExit: return os.EX_USAGE command = " ".join(command).strip() if not command: sys.stderr.write(os.path.basename(argv[0]) + ": Command must not be empty.\n") op.print_usage() return os.EX_USAGE prev = None while True: now = time.strftime(opts.timeformat) cmd = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) this = cmd.communicate()[0].split("\n") if this[-1] == "": del this[-1] changes = list(changed_lines(prev, this)) for marker,lineo,line in changes: print now + (opts.separator % (marker,)) + line prev = this time.sleep(opts.interval) if __name__ == "__main__": retval = main(sys.argv) sys.exit(retval)