You are not logged in.

#1 2023-12-21 11:19:28

swiftycode
Member
Registered: 2023-10-15
Posts: 8

Python3: get stdout of a command in real time

Hi everyone,

I need to write a Python script that can process/read and print the output (standard output) of a command in real time, line by line. The methods I found online doesn't quite work well, and in most cases the script can't read any standard output unless the invoked command exits/finishes. I have tried using the read line function and disabling line buffering, but it still doesn't work in most cases.

However, I should note that it works in rare circumstances, such as the ping command. I'm guessing that it's related to many programs not flushing the stdout pipe after each line of output.

Can anyone provide a working method? Here's the code I have currently:

import subprocess
import sys

if len(sys.argv)<2:
    print("No command specified")
    exit(1)
print(sys.argv[1:])
def splitarray_to_string(array: list) -> str:
    product=""
    for item in array:
        product+=item+" "
    return product.strip()
process = subprocess.Popen(splitarray_to_string(sys.argv[1:]), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=0, text=True)

while True:
    line=process.stdout.readline()
    if process.poll() != None:
        break
    if line != '':
        sys.stdout.write(line);sys.stdout.flush()
rc=process.poll()

Thanks!

Offline

#2 2023-12-21 20:35:14

seth
Member
Registered: 2012-09-03
Posts: 51,885

Re: Python3: get stdout of a command in real time

Try to goolge for "python3 fcntl O_NONBLOCK"

Offline

#3 2023-12-22 04:43:51

swiftycode
Member
Registered: 2023-10-15
Posts: 8

Re: Python3: get stdout of a command in real time

seth wrote:

Try to goolge for "python3 fcntl O_NONBLOCK"

One method I found online says that I have to set the flag of the stdout pipe to O_NONBLOCK. After inserting

fcntl.fcntl(process.stdout, fcntl.F_SETFL, os.O_NONBLOCK)

into my code before the read loop, I'm getting this error on the read function.

TypeError: underlying read() should have returned a bytes-like object, not 'NoneType'

Handling this error using

except TypeError:
    continue

doesn't fix anything at all (the same effect as before).

Offline

#5 2024-01-23 04:15:39

swiftycode
Member
Registered: 2023-10-15
Posts: 8

Re: Python3: get stdout of a command in real time

It would be highly appreciated if anyone can provide a working code implementation that I can directly use; it would save me time from trying to understand and test a bunch of solutions I found online. I would want the program output to behave exactly like terminal output, meaning that the stdout can be read in real time without any waiting or blocking.

Thanks!

P.S. Using asyncio's subprocess functions, which is a solution I found online, doesn't fix the problem for me.

Last edited by swiftycode (2024-01-23 04:24:27)

Offline

#6 2024-01-23 07:48:46

bulletmark
Member
From: Brisbane, Australia
Registered: 2013-10-22
Posts: 658

Re: Python3: get stdout of a command in real time

It's not clear which end of the stick you are trying to shake here? That example code runs another program and captures it's output. You say that example code works with ping, but not with other programs. So that must mean your example code works, and your problem is actually those "other" programs. Are they written in Python also, so are you really asking about them? If you are, then just run them with `python -u` instead of `python` (e.g. change the 1st shebang line to add that `-u`). Or change that/those programs to always add flush=True on all the `print` statements, e.g by wrapping `print(msg)` with `def log(msg): print(msg, flush=True)`.

Offline

Board footer

Powered by FluxBB