python os.popen返回的是字符串对象吗_Python - 如何将字符串传递给subprocess.Popen(使用stdin参数)?...

本文介绍了如何在Python中使用subprocess.Popen正确地将字符串作为输入(stdin)传递给子进程,包括使用 PIPE 参数、编码转换、以及避免内存问题的方法。解决方案包括使用Popen.input参数、创建管道和适配cStringIO.StringIO对象等。
摘要由CSDN通过智能技术生成

Python - 如何将字符串传递给subprocess.Popen(使用stdin参数)?

如果我执行以下操作:

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 "", 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对象不能足够接近文件duck以适应subprocess.Popen。 我该如何解决这个问题?

10个解决方案

276 votes

Popen.communicate()文档:

请注意,如果要将数据发送到   你需要的是进程的标准输入   用它创建Popen对象  标准输入=管道。 同样,得到任何东西   除了结果元组中的None之外,   你需要给stdout = PIPE和/或   stderr = PIPE也是。

替换os.popen *

pipe = os.popen(cmd, 'w', bufsize)

# ==>

pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin

警告使用communic()而不是   stdin.write(),stdout.read()或   stderr.read()以避免死锁   到任何其他OS管道缓冲区   填补和阻止孩子   处理。

所以你的例子可以写成如下:

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版本中,您可以使用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

# ->

jfs answered 2019-02-19T23:12:56Z

38 votes

我想出了这个解决方法:

>>> 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()

还有更好的吗?

Daryl Spitzer answered 2019-02-19T23:13:26Z

22 votes

我有点惊讶没有人建议创建一个管道,在我看来,这是将字符串传递给子进程的stdin最简单的方法:

read, write = os.pipe()

os.write(write, "stdin input here")

os.close(write)

subprocess.check_call(['your-command'], stdin=read)

Graham Christensen answered 2019-02-19T23:13:50Z

14 votes

我正在使用python3并发现你需要对你的字符串进行编码才能将它传递给stdin:

p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=PIPE)

out, err = p.communicate(input='one\ntwo\nthree\nfour\nfive\nsix\n'.encode())

print(out)

qed answered 2019-02-19T23:14:15Z

13 votes

“显然cStringIO.StringIO对象并不足够接近文件duck以适应subprocess.Popen”

:-)

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

Dan Lenski answered 2019-02-19T23:14:48Z

13 votes

如果您使用的是Python 3.4或更高版本,那么这是一个美丽的解决方案。 使用input参数而不是stdin参数,该参数接受字节参数:

output = subprocess.check_output(

["sed", "s/foo/bar/"],

input=b"foo",

)

Flimm answered 2019-02-19T23:15:13Z

8 votes

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()

Michael Waddell answered 2019-02-19T23:15:31Z

6 votes

"""

Ex: Dialog (2-way) with a Popen()

"""

p = subprocess.Popen('Your Command Here',

stdout=subprocess.PIPE,

stderr=subprocess.STDOUT,

stdin=PIPE,

shell=True,

bufsize=0)

p.stdin.write('START\n')

out = p.stdout.readline()

while out:

line = out

line = line.rstrip("\n")

if "WHATEVER1" in line:

pr = 1

p.stdin.write('DO 1\n')

out = p.stdout.readline()

continue

if "WHATEVER2" in line:

pr = 2

p.stdin.write('DO 2\n')

out = p.stdout.readline()

continue

"""

..........

"""

out = p.stdout.readline()

p.wait()

Lucien Hercaud answered 2019-02-19T23:15:50Z

5 votes

请注意File "/opt/local/stow/python-2.7.2/lib/python2.7/subprocess.py", line 1130, in _execute_child

self.pid = os.fork()

OSError: [Errno 12] Cannot allocate memory可能会给你带来麻烦ifs太大了,因为很明显父进程会在分配子子进程之前缓冲它,这意味着它需要“两倍”使用内存(至少根据“引擎盖下”的解释和 链接文档在这里找到)。 在我的特定情况下,s是一个首先完全展开的生成器,然后写入到stdin,因此父进程在生成子进程之前是巨大的,没有内存可以分叉它:

File "/opt/local/stow/python-2.7.2/lib/python2.7/subprocess.py", line 1130, in _execute_child

self.pid = os.fork()

OSError: [Errno 12] Cannot allocate memory

Lord Henry Wotton answered 2019-02-19T23:16:23Z

3 votes

p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)

p.stdin.write('one\n')

time.sleep(0.5)

p.stdin.write('two\n')

time.sleep(0.5)

p.stdin.write('three\n')

time.sleep(0.5)

testresult = p.communicate()[0]

time.sleep(0.5)

print(testresult)

dusan answered 2019-02-19T23:16:42Z

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值