2013-02-18 56 views
2

我有以下Python代碼片段,無法解釋爲什麼它的行爲方式如此。無法使用popen啓動兩個交互式shell

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" 

當我運行它,我得到以下的輸出:

[[email protected] ~]$ python test.py 
Checkpoint 1 
Checkpoint 2 
[1]+ Stopped     python test.py 
[[email protected] ~]$ [[email protected] ~]$ echo 'works1' 
works1 
[[email protected] ~]$ logout 
[[email protected] ~]$ fg  
python test.py 
[[email protected] ~]$ echo 'works2' 
works2 
[[email protected] ~]$ logout 
OK 
[[email protected] ~]$ 
  1. 爲什麼Python進程停止在第二POPEN電話嗎? (由tty輸入停止),以及如何避免它?
  2. 爲什麼在echo'works1'完成後我會收到註銷消息,以及如何避免它?
+0

您是否嘗試在通信調用結束時添加換行符? 'bash1.communicate(「echo'works1'\ n」)'。 – Bakuriu 2013-02-18 17:27:53

+0

我試過了,但結果是一樣的。 – 2013-02-18 17:33:51

回答

3

回答問題1:

這是因爲一個交互式的bash期望被附着到終端(「控制終端」)和以處理作業控制中斷取得它(例如控制 - Z)。第二次調用嘗試獲取終端但不能,因此暫時中止。

回答問題2:

communicate寫入其參數傳遞給子進程的標準輸入管道,然後關閉它。當stdin耗盡時Bash終止(就像在bash終端會話中輸入Control-D)。

如果你想保持bash的子進程的運行,然後寫它的標準輸入,而不是直接使用communicate如下:

bash1.stdin.write("echo 'works1'\n") 

你需要添加新行,如果你想命令實際執行, 順便一提。

A液:

如果你想運行兩個或更多的互動炮彈,你應該設置每個殼的標準輸入是一個pseudo-terminal,而不是一個子進程管道。

+0

我不明白爲什麼stdin = subprocess.PIPE不起作用。這是兩個獨立的管道,對嗎?那麼爲什麼2nd不會和1st共存呢?我不需要通過stdin發送任何命令,我只需要通過'-c'發送一個命令,但是我確實需要一個交互式shell,因爲我希望命令能夠使用用戶的正常別名和shell函數。我還需要一個pty嗎? – 2014-08-03 15:22:32

2

根據isedev提示,我打開了2個pseudoterminals。重要的是主進程(這個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" 

就是這樣。希望它能幫助別人!