How do you get the output of a command with multiple lines of output using pexpect?
This code works, albeit with the output smashed into one line:
child = pexpect.spawn('ping -c 3 1.1.1.1')
child.expect(pexpect.EOF)
print(child.before)
However, this code does not work:
child = pexpect.spawn('hostname')
child.expect(pexpect.EOF)
print(child.before)
child.seldline('ping -c 3 1.1.1.1')
child.expect(pexpect.EOF)
print(child.before)
How would I get this second code to work?
I have commands that I need to run to get connected (replaced here with hostname) and then commands that output mulitiple lines (replaced here with ping) that I cannot seem to get the output from. If I look for any string other than EOF, I get an EOF exception...
The commands I am actually running are here if you need proof:
The answer in this other question may be deprecated because this section of code copied exactly just outputs b''
over and over again.
The real question: Why the second example doesn't work.
The pexpect.spawn object ('child' here) points to a process id (PID). The example I was trying to use was not working because hostname
was running and then exiting. In my real usecase, I was using ssh
and then several other necessary steps before the long output command (represented by ping
here).
Starting your multi-step process with a command that keeps running will solve that issue. Either of these Examples will work:
child = pexpect.spawn('ssh user@host')
child = pexpect.spawn('bin/bash')
I switched to the latter which spins up a new shell that I can interact with. This allowed me to add some error handling to the ssh connection and reuse the code several times within the one shell.
Note that if you exit the ssh connection or bash shell respectively, you will need to spawn a new 'child' to send more commands.
Extra Detail: Fixing the first/working example's output.
This code will return the output of the last command without changing it.
def try_read(child):
"""Based on pexpect.pxssh.try_read_prompt"""
total_timeout = 3
timeout = 0.5
inter_char_timeout = 0.1
begin = time.time()
expired = 0
prompt = ''
while expired < total_timeout:
try:
prompt += child.read_nonblocking(size=1, timeout=timeout)
expired = time.time() - begin # updated total time expired
timeout = inter_char_timeout
except TimeoutError:
print("read ended with TimeoutError")
break
except pexpect.TIMEOUT:
print("read ended with pexpect.Timeout")
break
except pexpect.EOF:
print("read ended with pexpect.EOF")
break
return prompt