我有以下Python代码段,无法解释其行为方式的原因。
import subprocess
bash1 = subprocess.Popen(["/bin/bash","-l", "-i"], stdin=subprocess.PIPE)
print "Checkpoint 1"
bash2 = subprocess.Popen(["/bin/bash","-l", "-i"], stdin=subprocess.PIPE)
print "Checkpoint 2"
bash1.communicate("echo 'works1'")
bash2.communicate("echo 'works2'")
print "OK"
当我运行它时,我得到以下输出:
[user@localhost ~]$ python test.py
Checkpoint 1
Checkpoint 2
[1]+ Stopped python test.py
[user@localhost ~]$ [user@localhost ~]$ echo 'works1'
works1
[user@localhost ~]$ logout
[user@localhost ~]$ fg
python test.py
[user@localhost ~]$ echo 'works2'
works2
[user@localhost ~]$ logout
OK
[user@localhost ~]$
答案 0 :(得分:3)
回答问题1:
这是因为交互式bash shell期望附加到终端(“控制终端”)并获取它以便处理作业控制中断(例如Control-Z)。第二次调用尝试获取终端但不能,因此暂时暂停。
回答问题2:
communicate
将其参数写入子进程的stdin管道,然后将其关闭。 Bash在stdin耗尽时终止(就像在bash终端会话中输入Control-D一样)。
如果要保持bash子进程运行,请直接写入stdin而不是使用communicate
,如下所示:
bash1.stdin.write("echo 'works1'\n")
顺便说一句,如果你想要命令实际执行,你需要添加换行符。
解决方案:
如果要运行两个或更多交互式shell,则应将每个shell的stdin设置为pseudo-terminal而不是子进程PIPE。
答案 1 :(得分:2)
根据isedev提示,我打开了2个伪终端。重要的是master进程(这个python脚本)在master PTY文件上读写,而子子进程使用slave文件作为stdin,stdout和stderr。代码的底部部分仅用于测试一切是如何工作的。
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"
就是这样。希望它可以帮助别人!