Python-如何将字符串传递到subprocess.Popen(使用stdin参数)?
时间:2020-03-06 15:02:20 来源:igfitidea点击:
如果我执行以下操作:
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。我该如何解决?
解决方案
我想出了解决方法:
>>> 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()
有更好的吗?
"显然,cStringIO.StringIO对象与文件鸭子的距离不够近,无法适应subprocess.Popen"
:-)
恐怕不是。管道是低级OS概念,因此绝对需要由OS级文件描述符表示的文件对象。解决方法是正确的。
Popen.communicate()
文档:
Note that if you want to send data to the process’s stdin, you need to create the Popen object with stdin=PIPE. Similarly, to get anything other than None in the result tuple, you need to give stdout=PIPE and/or stderr=PIPE too. Replacing os.popen*
pipe = os.popen(cmd, 'w', bufsize) # ==> pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin
Warning Use communicate() rather than stdin.write(), stdout.read() or stderr.read() to avoid deadlocks due to any of the other OS pipe buffers filling up and blocking the child process.
因此,示例可以编写如下:
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 # ->
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)