-
-
Save sebclaeys/1232088 to your computer and use it in GitHub Desktop.
| import fcntl | |
| import os | |
| from subprocess import * | |
| def non_block_read(output): | |
| fd = output.fileno() | |
| fl = fcntl.fcntl(fd, fcntl.F_GETFL) | |
| fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) | |
| try: | |
| return output.read() | |
| except: | |
| return "" | |
| ############ | |
| # Use case # | |
| ############ | |
| sb = Popen("echo test; sleep 10000", shell=True, stdout=PIPE) | |
| sb.kill() | |
| sb.poll() # return -9 | |
| #sb.stdout.read() # Will block and will block forever cause nothing will come out since the job is done | |
| non_block_read(sb.stdout) # will return '' instead of hanging for ever | |
Thank you you saved my life :)
Note that fcntl isn't available on Windows. =_= ...
Using shell=True "makes a program vulnerable to shell injection, a serious security flaw which can result in arbitrary command execution. For this reason, the use of shell=True is strongly discouraged" . Is it possible to adapt this approach to shell=False?
Just look at the code: the shell=True is only there so that the example (which is in shell notation) can work:
sb = Popen("echo test; sleep 10000", shell=True, stdout=PIPE)If you don't use shell syntax, or rely on any other shell features, then you don't need shell=True.
This is much simpler:
p = Popen("echo test; sleep 10000", shell=True, stdout=PIPE)
for x in iter(p.stdout.readline, b''):
print(x)Thank you so much. I've been trying just about everything to get this working with a read -p "Type something" command inside a script (which outputs to stderr without a newline making readline() not work) and this is the only thing that has worked properly.
This is much simpler:
p = Popen("echo test; sleep 10000", shell=True, stdout=PIPE) for x in iter(p.stdout.readline, b''): print(x)
p.stdout.readline() blocks. That is why this gist is about non_blocking_read
Readline version (strips '\n')
def non_block_readline(output) -> str:
fd = output.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
try:
return output.readline().strip("\n")
except:
return ""Since Python 3.5 os.set_blocking can do exactly the same thing:
import os
from subprocess import *
sb = Popen("echo test; sleep 10000", shell=True, stdout=PIPE)
os.set_blocking(sb.stdout.fileno(), False) # That's what you are looking for
sb.kill()
sb.poll() # return -9
sb.stdout.read() # This is not going to block. When the pipe is empty it returns an empty string.
Note that fcntl isn't available on Windows.