5

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
  • python3.8.2 requires: filter_buf += s.decode("utf-8") Commented May 6, 2020 at 0:59

1 Answer 1

6

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] # 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.