PC System: Ubuntu 18.04
Python version: 3.6.9
When execute command like "adb logcat" by subprocess.Popen, I want to get the stdout and decide whether to stop the subprocess based on the keyword in it.
If the keyword does not appear for a long time, i will stop it too. The first attempt is as follows
import time
import subprocess
cmd = "adb logcat"
timeout = 10
adb_shell_pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, universal_newlines=True)
start_time = time.time()
for info in iter(adb_shell_pipe.stdout.readline, ""):
if "keyword" in info:
print("Find keyword!")
# Omit kill process
break
if time.time() - start_time > timeout:
print("Fail!")
# Omit kill process
break
The code succeeded in doing what I need, but I found that if there is no next output from the tenth seconds after the subprocess starts, the program will not end with "Fail!" until the next output.
I think it's because readline()
blocks to read the output. So, i set the stdout to non-block by fcntl
like the following code
import os
import time
import fcntl
import subprocess
# Command was replaced to create test scenarios
cmd = "adb shell"
timeout = 10
adb_shell_pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, universal_newlines=True)
fd = adb_shell_pipe.stdout.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
count = 0
start_time = time.time()
while adb_shell_pipe.poll() is None:
count += 1
info = adb_shell_pipe.stdout.readline()
if info and "keyword" in info:
print("Find keyword!")
# Omit kill process
break
if time.time() - start_time > timeout:
print("Fail!")
# Omit kill process
break
print(count)
# Output
Fail!
4131304
As shown above, the results were as expected. However, it execute readline()
4131304 times in 10 seconds, It may waste resources, and the fcntl
module cannot be used on Windows.
So, is there a more elegant, generic way to implement this requirement?