2011-08-26 29 views
2

我想为使用python的bash会话编写一个包装器。 我做的第一件事就是尝试产生一个bash过程,然后尝试读取其输出。像这样:使用子进程执行bash.Popen

from subprocess import Popen, PIPE 
bash = Popen("bash", stdin = PIPE, stdout = PIPE, stderr = PIPE) 
prompt = bash.stdout.read() 
bash.stdin.write("ls\n") 
ls_output = bash.stdout.read() 

但是这不起作用。首先,在创建过程之后从bash的stdout中读取失败,并且当我尝试写入stdin时,发现管道错误。 我在做什么错?

只是为了再次澄清,我没有兴趣在运行bash的通过一个命令,然后检索它的输出,我想有一些过程与我可以通过沟通管道运行bash命令。

+1

听起来像是你需要一个期待模块:http://www.noah.org/wiki/pexpect#Q:_Why_not_just_use_a_pipe_.28popen.28.29.29.3F –

+0

OK,我想我找到我需要的东西。 Python有一个名为pty的模块,它带有一个fork,它在类似终端的环境中产生一个子进程并返回一个读/写fd给它。然后,我可以对孩子执行任务。 –

回答

1

这工作:

import subprocess 
command = "ls" 
p = subprocess.Popen(command, shell=True, bufsize=0, stdout=subprocess.PIPE, universal_newlines=True) 
p.wait() 
output = p.stdout.read() 
p.stdout.close() 
+1

啊,但我没有试图运行一个命令。我希望bash进程在我与之交互时保持活跃状态​​。 –

+0

你也许可以在其他以后产卵一个过程,分析了前一个的输出。你有什么样的步骤/互动顺序? –

+0

注意,这在“上海”而不是“庆典”运行。有恼人的差异,比如“回声-n你好”不相同的方式工作。 –

0

为什么不使用cmd module/raw_input和subprocess.Popen(shell = True)?

0

你可以参考我的另一个答案:https://stackoverflow.com/a/43012138/3555925,它使用伪终端和选择在句柄标准输入/标准输出。

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

import os 
import sys 
import select 
import termios 
import tty 
import pty 
from subprocess import Popen 

command = 'bash' 
# command = 'docker run -it --rm centos /bin/bash'.split() 

# save original tty setting then set it to raw mode 
old_tty = termios.tcgetattr(sys.stdin) 
tty.setraw(sys.stdin.fileno()) 

# open pseudo-terminal to interact with subprocess 
master_fd, slave_fd = pty.openpty() 

# use os.setsid() make it run in a new process group, or bash job control will not be enabled 
p = Popen(command, 
      preexec_fn=os.setsid, 
      stdin=slave_fd, 
      stdout=slave_fd, 
      stderr=slave_fd, 
      universal_newlines=True) 

while p.poll() is None: 
    r, w, e = select.select([sys.stdin, master_fd], [], []) 
    if sys.stdin in r: 
     d = os.read(sys.stdin.fileno(), 10240) 
     os.write(master_fd, d) 
    elif master_fd in r: 
     o = os.read(master_fd, 10240) 
     if o: 
      os.write(sys.stdout.fileno(), o) 

# restore tty settings back 
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)