Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

#22 pexpect just duplicates stdin

closed-invalid
nobody
None
5
2010-03-17
2009-04-01
Nikolaus Rath
No

Hello,

I have a strange problem with pexpect:

$ cat test.py
#!/usr/bin/python

import pexpect

child = pexpect.spawn("./test.pl")

while True:
try:
line = raw_input()
except EOFError:
break

child.sendline(line)
print child.readline().rstrip("\r\n")

child.close()

$ cat test.pl
#!/usr/bin/perl
# Replace all digits by __
while (<>) {
s/[0-9]+/__/g;
print;
}

$ echo bla24fasel | ./test.pl
bla__fasel

$ echo bla24fasel | ./test.py
bla24fasel

Why doesn't the last command return bla__fasel too?

I extracted this example from an even stranger problem in a bigger
program. In there, pexpect sometimes returns both the string send with
sendline() *and* the output of the child program, sometimes the
correct output of the child, and sometimes only the input it has send
to the child. I couldn't figure out a pattern, but the above example
always produces the same result.

Discussion

  • Nikolaus Rath
    Nikolaus Rath
    2009-04-01

     
    Attachments
  • Nikolaus Rath
    Nikolaus Rath
    2009-04-01

     
    Attachments
  • Noah Spurrier
    Noah Spurrier
    2010-03-17

    You are reading back the echo of the data you sent to the child. This is expected behavior. This behavior can be confusing because you started a perl script and didn't program it to echo stdin. The reason is because the perl script is started in a pseudo-tty so there is actually a TTY device driver between your python script and your perl script. The TTY is echoing back stdin. This is the same thing that happens in a bash shell. You see what you type not because Bash is echoing but because the TTY device driver is echoing.

    In Pexpect you can turn this off using child.setecho(False). See the doc string for "setecho()"

    I rewrote your example to illustrate what is going on.

    #!/usr/bin/python
    import pexpect
    child = pexpect.spawn("./test.pl")
    print ("# Child echo mode: " + str(child.getecho()) )
    print ("# Read one line from my stdin.")
    try:
    line = raw_input()
    except EOFError, e:
    print ("# Got EOFError from reading raw input. This is expected.")
    print ("# Sending line read from raw_input to the child.")
    child.sendline(line)
    print ("# First: read and print a single line from the child.")
    print child.readline().rstrip("\r\n")
    print ("# Second: read and print a single line from the child.")
    print child.readline().rstrip("\r\n")
    print ("# Child echo mode: " + str(child.getecho()) )
    print ("# Closing child.")
    child.close()

     
  • Noah Spurrier
    Noah Spurrier
    2010-03-17

    • status: open --> closed-invalid
     
  • Noah Spurrier
    Noah Spurrier
    2010-03-17

    The tracker form messes up the formatting of code, so I am submitting again. You should be able to fix the formatting even with indentation lost. Basically, the try clause has only one statement and the except clause also has only one statement.

    #!/usr/bin/python
    import pexpect
    child = pexpect.spawn("./test.pl")
    print ("# Child echo mode: " + str(child.getecho()) )
    print ("# Read one line from my stdin.")

    try:
    line = raw_input()
    except EOFError, e:
    print ("# Got EOFError from reading raw input. This is expected.")

    print ("# Sending line read from raw_input to the child.")
    child.sendline(line)
    print ("# First: read and print a single line from the child.")
    print child.readline().rstrip("\r\n")
    print ("# Second: read and print a single line from the child.")
    print child.readline().rstrip("\r\n")
    print ("# Child echo mode: " + str(child.getecho()) )
    print ("# Closing child.")
    child.close()