问题
The general problem is, that I want to use pexpect to call scripts that require sudo rights, but I don't always want to enter my password (only once).
My plan is to use pexpect to spawn a bash session with sudo rights and to call scripts from there. Basically I always want to keep the session busy, whenever one script stopped, I want to start another. But while the scripts are running, I want the user to have control. Meaning:
The scripts should be called after something like expect("root@"), so whenever the session is idle, it starts another script. While the scripts are running interact() is giving the user control of possible input he wants to give.
My idea was to use different threads to to solve this problem. My code (for the proof of concept) looks like this:
import pexpect
import threading
class BashInteractThread(threading.Thread):
def __init__(self, process):
threading.Thread.__init__(self)
self.pproc = process
def run(self):
self.pproc.interact()
s = pexpect.spawn("/bin/bash", ['-i', '-c', "sudo bash"])
it = BashInteractThread(s)
it.start()
s.expect("root@")
s.sendline("cd ~")
while(s.isalive()):
pass
s.close()
When I call this script, it does not give me any output, but the process seems to have been started. Still, I cannot CTRL-C or CTRL-D to kill the process - I have to kill the process separately. The behavior I would expect, would be to get prompted to enter a password and after that it should automatically change the directory to the home directory. I don't exactly know why it does not work, but I guess the output only gets forwarded either to interact() or to expect().
Does anyone have an idea on how to solve this? Thanks in advance.
回答1:
You can take advantage of interact(output_filter=func)
. I just wrote a simple example (no coding style!). What it does is spawn a Bash
shell and repeatedly invoke Python
for the user to interact with. To exit the trap, just input (or print) the magic words LET ME OUT
.
expect()
would not work anymore after interact()
, so need to do the pattern matching work manually.
The code:
[STEP 101] # cat interact_with_filter.py
import pexpect, re
def output_filter(s):
global proc, bash_prompt, filter_buf, filter_buf_size, let_me_out
filter_buf += s
filter_buf = filter_buf[-filter_buf_size:]
if "LET ME OUT" in filter_buf:
let_me_out = True
if bash_prompt.search(filter_buf):
if let_me_out:
proc.sendline('exit')
proc.expect(pexpect.EOF)
proc.wait()
else:
proc.sendline('python')
return s
filter_buf = ''
filter_buf_size = 256
let_me_out = False
bash_prompt = re.compile('bash-[.0-9]+[$#] $')
proc = pexpect.spawn('bash --noprofile --norc')
proc.interact(output_filter=output_filter)
print "BYE"
[STEP 102] #
Let's try it:
[STEP 102] # python interact_with_filter.py
bash-4.4# python
Python 2.7.9 (default, Jun 29 2016, 13:08:31)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> exit() <---- user input
bash-4.4# python
Python 2.7.9 (default, Jun 29 2016, 13:08:31)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> exit() <---- user input
bash-4.4# python
Python 2.7.9 (default, Jun 29 2016, 13:08:31)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> LET ME OUT <---- user input
File "<stdin>", line 1
LET ME OUT
^
SyntaxError: invalid syntax
>>> exit() <---- user input
bash-4.4# BYE
[STEP 103] #
来源:https://stackoverflow.com/questions/43371249/using-expect-and-interact-simultaneously-in-pexpect