I have scripts for hardware evaluation/test that have outgrown Bash and are moving to Python 3. All is going extremely well, except for one stumbling block: I'm having trouble finding a Python replacement for Bash's read -rs -t1 -n1
command, which waits up to a second for a character to be typed before returning, which I use to perform background hardware safety checks (like, "is it on fire yet?") and display a spinner while waiting for user input.
However, I'm having trouble finding a "pythonic" replacement. The closest I've found so far is from Rosetta Code and here on StackExchange, all of which seem too low-level.
The key missing element appears to be Python's lack of a high-level capability to do a non-blocking read from stdin, at the level of Bash's read
command.
Cross-platform (Win/Mac/Lin) functionality is desired, but GNU/POSIX/Linux-only will do for now.
Is there a standard high-level way to do this under Python 3?
After trying several packages beyond those mentioned in the question (such as the stdin
package), I finally decided to go back to where I began:
def bash_read(optstr="-rs -t1 -n1"):
child = subprocess.Popen(["bash", "-c", "if read {}; then echo -n \"$REPLY\"; fi".format(optstr)], stdout=subprocess.PIPE)
reply = child.communicate()[0] # stdout content
return reply
The optstr
parameter is defaulted to the Bash read
options I tend to use most, however other options may be substituted as desired.
The above function simplifies moving my scripts to Python. But is it truly Pythonic? Well, yes! In the sense of using the right tool for the job.
The above gets simpler once 3.7 makes its way into the distros, needing only a single call to subprocess.run()
to get the return code and the text from the command's stdout and stderr.