harperville
harperville

Reputation: 7629

Python pexpect returning the command and the output from the command

I want to connect to a server that's running CLISH, supply a password when a password prompt is given (works), then issue a "shell" command to bump me to a bash shell (works), then test for the presence of a file and print "true" if it's missing or "" (empty string) if it's present (works).

What doesn't work is what I'm reading back into my scripts using "pexpect.before". I've asked pexpect to expect the basic prompt, then give me 'before', from what I understand is: "What do you see on your screen before the prompt was matched?" Not only am I getting my "true" or "" (empty string) as expected, I'm also getting the command back that I issued to test for the existence of the file.

For example, if I SSH directly to the machine, I would do: password:

What my script is returning is the command and the response (the question and the answer):

[ ! -f '/etc/logrotate.d/nginx' ] && echo 'true'

true

I just want the response, which is either "true" or "". I am getting the response but I'm also getting the command that was issued.

Can you see what I'm doing wrong? Please help! I'd like to continue using pexpect because I have more complicated "expectations" with my SSH sessions.

This is my code:

def connection(cmd):
    msg_newkey = 'Are you sure you want to continue connecting'
    p=pexpect.spawn('ssh '+user+'@'+host)
    msg = '''Super long welcome message containing your canned warning message, etc.
          myuser@'''+myhost+''''s password:'''
    i=p.expect([msg_newkey,'password:',pexpect.EOF])
    if i==0:
        print "Accepting key."
        p.sendline('yes')
        i=p.expect([msg_newkey,'password:',pexpect.EOF])
    if i==1:
        print "Supplying password"
        p.sendline(passwd)
    elif i==2:
        if "No route to host" in p.before:
            return p.before
        else:
            pass    # Add no functionality, just saying "move on"
    i=p.expect(['MYCLISHPROMPT>',pexpect.EOF])
    if i==0:
            p.sendline('shell')
    i=p.expect(['.*@.*\$',pexpect.EOF])
    if i==0:
            p.sendline(cmd)
    p.expect(['myuser@myhost:',pexpect.EOF])
    return p.before

 def look_for_file(step, filename, mytest):
    cmd = "[ ! -f '"+filename+"' ] && echo '"+mytest+"'"
    results = connection(cmd)
    print "***"+str(result)+"***"
    assert (results == '' or results == 0), "Step failed!  Error: "+results

Upvotes: 2

Views: 12324

Answers (2)

Bill Agee
Bill Agee

Reputation: 3646

I ran into this problem in a script in which I needed to set the pexpect log to sys.stdout, as shown below:

    shell = pexpect.spawn("bash")
    shell.logfile = sys.stdout

I tried the solutions suggested in the other answers here with no success; strings passed to sendline() were printed to the log no matter what.

However, I found that temporarily disabling the pexpect log seems to solve the problem:

    shell.logfile = None
    shell.sendline(MY_STRING)
    shell.logfile = sys.stdout

Upvotes: 1

Edu
Edu

Reputation: 2052

There's a function setecho (and it's pair getecho) that should control whether the string in sendline will be echoed back.

setecho(self, state)
    This sets the terminal echo mode on or off. Note that anything the
    child sent before the echo will be lost, so you should be sure that
    your input buffer is empty before you call setecho().

However, this is not apparently working in all situations and you need to use some workarounds. One is to turn of echo in bash as in this answer. Another one is to user pexpect's function readline or readlines to read the output and discard the first line which echoes the command given.

Upvotes: 2

Related Questions