Using expect() and interact() simultaneously in pexpect

狂风中的少年 提交于 2019-12-21 06:29:27

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!