2010-09-22 142 views
0

我有以下Python代碼之間進行通信:使用文件描述符過程

import pty 
import subprocess 
os=subprocess.os 
from subprocess import PIPE 
import time 
import resource 

pipe=subprocess.Popen(["cat"], stdin=PIPE, stdout=PIPE, stderr=PIPE, \ 
         close_fds=True) 
skip=[f.fileno() for f in (pipe.stdin, pipe.stdout, pipe.stderr)] 
pid, child_fd = pty.fork() 
if(pid==0): 
    max_fd=resource.getrlimit(resource.RLIMIT_NOFILE)[0] 
    fd=3 
    while fd<max_fd: 
     if(fd not in skip): 
      try: 
       os.close(fd) 
      except OSError: 
       pass 
      fd+=1 
     enviroment=os.environ.copy() 
     enviroment.update({"FD": str(pipe.stdin.fileno())}) 
     os.execvpe("zsh", ["-i", "-s"], enviroment) 
else: 
    os.write(child_fd, "echo a >&$FD\n") 
    time.sleep(1) 
    print pipe.stdout.read(2) 

如何我把它改寫,以便它不會使用Popencat?我需要一種方法來傳遞在交互式shell中運行的shell函數中的數據,該函數不會與其他函數創建的數據混合(因此我不能使用stdout或stderr)。

+0

爲什麼你不能直接''subprocess.Popen()'shell? – llasram 2010-09-22 15:30:16

+0

@llasram,因爲我需要一個交互式shell來捕獲傳遞給完成內建compadd的參數。沒有tty - 沒有互動 - 沒有完成。 – ZyX 2010-09-22 18:33:21

+0

我不是很追隨...你能提供一個具體的例子嗎? – llasram 2010-09-22 19:26:45

回答

1

好吧,我想我現在已經掌握了你的問題,並且看到了你可以採取的兩種不同的方法。

如果您絕對要在子進程中提供已打開文件描述符的shell,那麼可以用os.pipe()的調用替換Popen()cat。這會給你一對連接的真實文件描述符(不是Python file對象)。任何寫入第二個文件描述符的內容都可以從第一個文件描述符中讀取,替換您的陪審團操縱的cat-管道。 (雖然「貓管」很有趣......)。如果您需要雙向對,套接字對(socket.socketpair())也可用於實現相同的目的。

或者,您可以通過使用命名管道(又名FIFO)進一步簡化您的生活。如果您對設施不熟悉,則命名管道是位於文件系統名稱空間中的單向管道。 os.mkfifo()函數將在文件系統上創建管道。然後,您可以打開管道讀取主進程中的內容,並打開它以便從shell子進程寫入/直接輸出。這應該簡化您的代碼並打開使用現有庫如Pexpect與shell進行交互的選項。

+0

謝謝,我沒有使用'mkfifo',因爲它會創建新文件。我嘗試使用'os.pipe()',但未能猜到我應該在子腳本中使用第二個fd,並首先在父級中使用。使用'pty.fork'的想法是在考察了pexpect的源代碼之後出現的。 – ZyX 2010-09-23 09:20:38