使用 subprocess.Popen 执行 bash
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7206519/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Executing bash with subprocess.Popen
提问by Dany Zatuchna
I'm trying to write a wrapper for a bash session using python. The first thing I did was just try to spawn a bash process, and then try to read its output. like this:
我正在尝试使用 python 为 bash 会话编写一个包装器。我做的第一件事就是尝试生成一个 bash 进程,然后尝试读取它的输出。像这样:
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()
But this does not work. First, reading from bash's stdout after creating the process fails, and when I try to write to stdin, I get a broken pipe error. What am I doing wrong?
但这不起作用。首先,在创建进程后从 bash 的标准输出读取失败,当我尝试写入标准输入时,出现管道损坏错误。我究竟做错了什么?
Just to clarify again, I'm not interested in running a single command via bash and then retrieving its output, I want to have a bash session running in some process with which I can communicate via pipes.
再次澄清一下,我对通过 bash 运行单个命令然后检索其输出不感兴趣,我希望在某个进程中运行一个 bash 会话,我可以通过管道与之进行通信。
回答by Gabriel Ross
This works:
这有效:
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()
回答by a3nm
The read()call is blocking, so it reads the output of the first command and hangs because further data could still arrive (ie. bashis still running). To perform a non-blocking read, see Non-blocking read on a subprocess.PIPE in python.
的read()呼叫被阻塞,所以它读取所述第一命令和挂起因为进一步的数据仍然可以到达(即输出bash仍在运行)。要执行非阻塞读取,请参阅python 中 subprocess.PIPE 上的非阻塞读取。
回答by Jonathan Sternberg
Why don't you just use the cmd module/raw_input along with subprocess.Popen(shell = True)?
为什么不直接使用cmd 模块/raw_input 和 subprocess.Popen(shell = True)?
回答by Liao
You can refer to my another answer: https://stackoverflow.com/a/43012138/3555925, which use pseudo-terminal and select in handle stdin/stdout.
您可以参考我的另一个答案:https: //stackoverflow.com/a/43012138/3555925,它使用伪终端并在句柄 stdin/stdout 中选择。
#!/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)

