如果我这样做:

import subprocess
from cStringIO import StringIO
subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=StringIO('one\ntwo\nthree\nfour\nfive\nsix\n')).communicate()[0]

我得到:

Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 533, in __init__
    (p2cread, p2cwrite,
  File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 830, in _get_handles
    p2cread = stdin.fileno()
AttributeError: 'cStringIO.StringI' object has no attribute 'fileno'

显然是cStringIO。StringIO对象的嘎嘎声不够接近文件鸭子,不适合subprocess.Popen。我怎么解决这个问题呢?


当前回答

显然是cStringIO。StringIO对象的嘎嘎声不够接近 适合子进程的文件鸭。Popen

恐怕不行。管道是一个低级的操作系统概念,因此它绝对需要一个由操作系统级文件描述符表示的文件对象。你的解决方法是正确的。

其他回答

Beware that Popen.communicate(input=s)may give you trouble ifsis too big, because apparently the parent process will buffer it before forking the child subprocess, meaning it needs "twice as much" used memory at that point (at least according to the "under the hood" explanation and linked documentation found here). In my particular case,swas a generator that was first fully expanded and only then written tostdin so the parent process was huge right before the child was spawned, and no memory was left to fork it:

文件“/opt/local/stow/python-2.7.2/lib/python2.7/subprocess.py”,第1130行,在_execute_child中 自我。Pid = os.fork() OSError: [Errno 12]不能分配内存

from subprocess import Popen, PIPE
from tempfile import SpooledTemporaryFile as tempfile
f = tempfile()
f.write('one\ntwo\nthree\nfour\nfive\nsix\n')
f.seek(0)
print Popen(['/bin/grep','f'],stdout=PIPE,stdin=f).stdout.read()
f.close()

Popen.communicate()的文档:

请注意,如果要将数据发送到 这个过程是标准的,你需要 创建Popen对象 stdin =管。同样,要得到任何东西 除了结果元组中的None, 你需要给stdout=PIPE和/或 stderr =管。 取代os.popen *

    pipe = os.popen(cmd, 'w', bufsize)
    # ==>
    pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin

警告使用communication()代替 Stdin.write (), stdout.read()或 Stderr.read()避免死锁 到任何其他操作系统管道缓冲区 填充和阻塞孩子 的过程。

所以你的例子可以写成这样:

from subprocess import Popen, PIPE, STDOUT

p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)    
grep_stdout = p.communicate(input=b'one\ntwo\nthree\nfour\nfive\nsix\n')[0]
print(grep_stdout.decode())
# -> four
# -> five
# ->

在Python 3.5+(编码为3.6+)上,你可以使用subprocess.run,将输入作为字符串传递给外部命令,并在一次调用中获得其退出状态和输出作为字符串返回:

#!/usr/bin/env python3
from subprocess import run, PIPE

p = run(['grep', 'f'], stdout=PIPE,
        input='one\ntwo\nthree\nfour\nfive\nsix\n', encoding='ascii')
print(p.returncode)
# -> 0
print(p.stdout)
# -> four
# -> five
# -> 

如果您使用的是Python 3.4或更高版本,那么有一个很好的解决方案。使用input参数而不是stdin参数,它接受bytes参数:

output_bytes = subprocess.check_output(
    ["sed", "s/foo/bar/"],
    input=b"foo",
)

这适用于check_output和run,但不适用于call或check_call。

在Python 3.7+中,你还可以添加text=True,使check_output接受一个字符串作为输入并返回一个字符串(而不是字节):

output_string = subprocess.check_output(
    ["sed", "s/foo/bar/"],
    input="foo",
    text=True,
)

我想出了一个变通办法:

>>> p = subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=subprocess.PIPE)
>>> p.stdin.write(b'one\ntwo\nthree\nfour\nfive\nsix\n') #expects a bytes type object
>>> p.communicate()[0]
'four\nfive\n'
>>> p.stdin.close()

还有更好的吗?