How do I pass a string into subprocess.Popen (using the stdin argument)?
Как мне передать строку в 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 "<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 недостаточно крякает к утке файла, чтобы соответствовать подпроцессу.Popen. Как мне обойти это?
Обратите внимание, что если вы хотите отправить данные в stdin процесса, вам нужно создать объект Popen с помощью stdin=PIPE . Аналогично, чтобы получить что-либо, кроме None , в результирующем кортеже, вам также нужно указать stdout=PIPE и / или stderr=PIPE .
Предупреждение Используйте communicate() вместо 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 + для encoding) вы могли бы использовать 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 # ->
Ответ 2
Я нашел этот обходной путь:
>>> 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()
Есть ли вариант получше?
Ответ 3
Есть прекрасное решение, если вы используете Python 3.4 или выше. Используйте input аргумент вместо stdin аргумента, который принимает аргумент bytes:
В Python 3.7+ вы также можете добавить, text=True чтобы заставить check_output принимать строку в качестве входных данных и возвращать строку (вместо bytes):