0

Issue

Conflict with STDIN when executing these two functions. What would cause the second function to not read STDIN correctly? If the first function is not executed, the second function has no issue reading the input.

To clear STDIN buffer I've tried:

'sys.stdin.flush'

'tcflush(sys.stdin, TCIOFLUSH)'

Python Code

import sys, select

def stdin_read():

    print "[stdin read] You must answer Y/N and press ENTER"
    sys.stdout.flush()
    response = sys.stdin.read(1)
    print "You said '{}'".format(response)


def stdin_timeout():

    print "[stdin timeout] You must answer YES / NO in 10 seconds and press ENTER"
    sys.stdout.flush()

    sys.stdin.flush()

    i, o, e = select.select( [sys.stdin], [], [], 10 )

    if (i):
        print "You said '{}'".format(sys.stdin.readline().strip())
        exit(0)
    else:
        print "You said nothing!"
        exit(1)


stdin_read()
stdin_timeout()

Python Output Both Functions:

:~# python input.py
[stdin read] You must answer Y/N and press ENTER
n
You said 'n'
[stdin timeout] You must answer YES / NO in 10 seconds and press ENTER
no
You said ''
:~# no
-bash: no: command not found

Python Output Second Function

~# python input.py
[stdin timeout] You must answer YES / NO in 10 seconds and press ENTER
no
You said 'no'

1 Answer 1

1

The problem arises from the behaviour of stdin flushing in unix

I'll answer by commmenting your code:

import sys, select

def stdin_read():

    print "[stdin read] You must answer Y/N and press ENTER"
    # sys.stdout.flush() # not needed
    # you are reading one byte here, but the user enters at least two bytes
    # (e.g 'y' + LF(enter key)) so the LF byte (and possibly additional bytes)
    # remain in the stdin buffer.
    response = sys.stdin.read(1) # (->LF REMAINS)
    print "You said '{}'".format(response)


def stdin_timeout():

    print "[stdin timeout] You must answer YES / NO in 10 seconds and press ENTER"
    #sys.stdout.flush() #  not needed
    # the behaviour of stdin flushing in unix is not defined (see 
    # link above)
    sys.stdin.flush()
    # thus the LF still remains in the stdin buffer

    # the select call blocks until the file discriptor is 'ready' for
    # the corresponding i/o operation. DISCLAIMER: assumptions are
    # following.... By default python does a open call which uses
    # buffered reads, so even if you did a read(1) it will likely read
    # more data from stdin and the select call blocks until the next LF
    # arrives.
    i, o, e = select.select( [sys.stdin], [], [], 10 )

    if (i):
        # you are just reading the left over bytes from above (->LF REMAINS)
        print "You said '{}'".format(sys.stdin.readline().strip())
        # Proof: readline() again:
        print "You missed '{}'".format(sys.stdin.readline().strip())
        exit(0)
    else:
        print "You said nothing!"
        exit(1)


stdin_read()
stdin_timeout()

But maybe it would be better to use another approach Keyboard input with timeout in Python

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.