Created
November 25, 2020 21:10
-
-
Save devilholk/46a0477bea4d0bf836563199afb18723 to your computer and use it in GitHub Desktop.
Watch command output on linux [WIP]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys, time, subprocess, threading, queue, os, fcntl | |
''' | |
For some reason, even with all the flushing, if python is running buffered (without -u), it will sometimes not flush! | |
Until I can figure this one out I'll use -u | |
Even with -u it sometimes will output stdout and stderr in different order, some buffering somewhere is messing things up. | |
As is this is still a decent tool for watching output that contains ANSI escapes watch -c won't manage. | |
''' | |
clear_cmd = b'\x1b[H\x1b[2J\x1b[3J' | |
output_lock = threading.Lock() | |
class buffer_node(threading.Thread): | |
def __init__(self, source_fd, dest_stream, pending, output_lock): | |
super().__init__() | |
self.source = os.fdopen(source_fd, 'rb', buffering=0) | |
self.dest = dest_stream | |
self.pending = pending | |
self.output_lock = output_lock | |
def run(self): | |
while 1: | |
try: | |
data = self.source.read() | |
except ValueError: | |
break | |
except OSError: | |
break | |
if self.pending.empty(): | |
self.dest.write(data) | |
else: | |
with self.output_lock: | |
while True: | |
try: | |
pending_data, pending_flush = self.pending.get_nowait() | |
self.dest.write(pending_data) | |
if pending_flush: | |
self.dest.flush() | |
except queue.Empty: | |
break | |
self.dest.write(data) | |
def run_command(cmd, header=None): | |
#Create queue | |
pending = queue.Queue() | |
#Add clear ANSI command and header | |
if header: | |
pending.put((clear_cmd + bytes(header, sys.getdefaultencoding()), True)) | |
else: | |
pending.put((clear_cmd, True)) | |
#Create pipes | |
stderr_r, stderr_w = os.pipe2(0) | |
stdout_r, stdout_w = os.pipe2(0) | |
#Create buffer processors | |
stdout_buffer = buffer_node(stdout_r, sys.stdout.buffer, pending, output_lock) | |
stderr_buffer = buffer_node(stderr_r, sys.stderr.buffer, pending, output_lock) | |
#Start threads | |
stdout_buffer.start() | |
stderr_buffer.start() | |
#Create output streams | |
child_stderr = os.fdopen(stderr_w, 'wb', buffering=0) | |
child_stdout = os.fdopen(stdout_w, 'wb', buffering=0) | |
#Execute command | |
subprocess.call(cmd, stderr=child_stderr, stdout=child_stdout, stdin=subprocess.DEVNULL, bufsize=0) | |
child_stderr.flush() | |
child_stdout.flush() | |
child_stderr.close() | |
child_stdout.close() | |
stdout_buffer.source.flush() | |
stderr_buffer.source.flush() | |
stdout_buffer.source.close() | |
stderr_buffer.source.close() | |
sys.stdout.flush() | |
sys.stderr.flush() | |
wait = 1 | |
cmd = sys.argv[1:] | |
while True: | |
run_command(cmd, f'\x1b[3m{time.ctime()}\x1b[23m - Every \x1b[1m{wait}\x1b[21m seconds, execute: \x1b[3;1m{" ".join(cmd)}\x1b[23;21m\n\n') | |
time.sleep(wait) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment