I have the following Python snippet, and cannot explain why it behaves the way it does.
import subprocess
bash1 = subprocess.Popen([\"/bin/bash\",\"-l\", \"-i\
Answer to question 1:
This is because an interactive bash shell expects to be attached to a terminal (the 'controlling terminal') and acquire it in order to process job control interrupts (e.g. Control-Z). The second invocation tries to acquire the terminal but can't, so gets temporarily suspended.
Answer to question 2:
communicate
writes its argument to the stdin pipe of the child process and then closes it. Bash terminates when its stdin is exhausted (it is like entering Control-D in a bash terminal session).
If you want to keep the bash child process running, then write to its stdin directly rather than use communicate
as follows:
bash1.stdin.write("echo 'works1'\n")
You do need to add the newline if you want the command to actually execute, by the way.
A solution:
If you want to run two or more interactive shells, you should setup the stdin of each shell to be a pseudo-terminal rather than a subprocess PIPE.
According to the isedev hint, I opened 2 pseudoterminals. Important thing is that master process (this python script) reads and writes on the master PTY file, while child subprocess uses slave file as stdin, stdout and stderr. Bottom part of the code is just for testing how everything works.
import subprocess
import os
import pty
import select
import time
# according to> http://fleckenzwerg2000.blogspot.com/2011/10/running-and-controlling-gnu-screen-from.html
(master1, slave1) = pty.openpty()
bash1 = subprocess.Popen(["bash", "-l", "-i"], stdin=slave1, stdout=slave1, stderr=slave1)
(master2, slave2) = pty.openpty()
bash2 = subprocess.Popen(["bash", "-l", "-i"], stdin=slave2, stdout=slave2, stderr=slave2)
data = "echo 'bla'\n"
## taken from> http://stackoverflow.com/questions/14564904/how-to-send-tab-key-to-python-subprocesss-stdin
def write_all(masterPTY, data):
"""Successively write all of data into a file-descriptor."""
while data:
chars_written = os.write(masterPTY, data)
data = data[chars_written:]
return data
def read_all(masterPTY):
r,w,x = select.select([masterPTY], [], [], 10)
if r:
data = os.read(masterPTY, 1024)
return data
write_all(master1, "echo 'bla1'\n")
write_all(master2, "echo 'bla2'\n")
time.sleep(1)
print read_all(master1)
write_all(master1, "echo 'bla1'\n")
time.sleep(1)
print read_all(master2)
time.sleep(1)
os.close(master1)
os.close(slave1)
os.close(master2)
os.close(slave2)
bash1.terminate()
bash2.terminate()
print "OK"
That is it. Hope it helps someone!