How to start a shell in a separate process and get automatic termination? (Python)

I have a linux application that receives input from some device. This input should be directed to the shell process so that it emulates a standard shell to the user. So far, I have done this by creating a process that runs '/ bin / sh', and I have redirected its input, output and stderr as follows:

import subprocess p = subprocess.Popen(shell=False, args=['/bin/sh'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) _make_nonblocking(p.stdout) # sets O_NONBLOCK _make_nonblocking(p.stderr) 

When I just pass the command, everything works:

 p.stdin.write('pwd\n') p.stdout.read() '/home/dave\n' 

For automatic completion, I tried to write:

 p.stdin.write('ls s\t') p.stdout.read() IOError: [Errno 11] Resource temporarily unavailable 

I expect to get a list of possible completions, but nothing will happen until I put '\ n' in stdin. (Also, there was nothing in stderr).

I looked at the telnetd code and saw the use of pty. I tried using pty.openpty () and setting slave as stdin, but that didn't work either. How to do it?

UPDATE: I used the -i option, as suggested. Now I have a problem that as soon as I use Popen and press ENTER, the python shell moves to the background as follows:

 >>> p = subprocess.Popen(shell=False, args=['/bin/sh', '-i'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) >>> <ENTER> [1]+ Stopped ipython $ 
+2
source share
2 answers

In the end, in order to completely solve all the problems, I had to do a few things:

  • configure the pty device (using the pty module in python).
  • set the appropriate flags using termios (echo, signal processing, etc.).
  • start a new session (so that the signals do not extend to the original process).
  • open the pty device with an unbuffered file (passing 0 to bufsize).

This is the code that works:

 def prepare(): os.setsid() # start a new detached session tty.setcbreak(sys.stdin) # set standard input to cbreak mode old = termios.tcgetattr(sys.stdin) old[0] |= termios.BRKINT # transforms break to SIGINT old[3] &= termios.ICANON # non-canonical mode old[3] |= termios.ECHO | termios.ISIG # set echo and signal characters handling cc = old[6] # make input unbuffered cc[termios.VMIN] = 1 cc[termios.VTIME] = 0 termios.tcsetattr(sys.stdin, termios.TCSANOW, old) master, slave = pty.openpty() master = os.fdopen(master, 'rb+wb', 0) # open file in an unbuffered mode _make_non_blocking(master) prog = subprocess.Popen(shell=False, args=['/bin/sh', '-i'], stdin=slave, stdout=slave, stderr=subprocess.STDOUT, preexec_fn=prepare) 
+3
source

With bash autocomplete only works interactively:

 -i If the -i option is present, the shell is interactive. 

This will do the right emulation, including displaying a tooltip and all the usual things.

+5
source

Source: https://habr.com/ru/post/987155/


All Articles