Модуль подпроцесса Python, как мне дать ввод первой из серии переданных команд? - PullRequest
5 голосов
/ 22 февраля 2011

Я пытаюсь использовать модуль подпроцесса Python.Что мне нужно, так это отправить входные данные первому процессу, чьи выходные данные становятся входными данными второго процесса.Ситуация в основном почти такая же, как в примере, приведенном здесь в документации: http://docs.python.org/library/subprocess.html#replacing-shell-pipeline, за исключением того, что мне нужно ввести первую команду.Вот этот пример скопирован:

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]

Если мы изменим первую строку на:

p1 = Popen(["cat"], stdout=PIPE, stdin=PIPE)

Как мне предоставить входную строку для процесса?Если я попытаюсь сделать это, изменив последнюю строку на:

output = p2.communicate(input=inputstring)[0]

Это не сработает.

У меня есть рабочая версия, которая просто хранит вывод первой команды встрока, а затем передает это второй команде.Это не страшно, так как практически нет параллелизма, который можно было бы использовать (в моем реальном случае использования первая команда довольно быстро выйдет и выдаст все свои выходные данные в конце).Вот рабочая версия в полном объеме:

import subprocess

simple = """Writing some text
with some lines in which the
word line occurs but others
where it does
not
"""

def run ():
  catcommand = [ "cat" ]
  catprocess = subprocess.Popen(catcommand,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
  (catout, caterr) = catprocess.communicate(input=simple)
  grepcommand = [ "grep", "line" ]
  grepprocess = subprocess.Popen(grepcommand,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
  (grepout, greperr) = grepprocess.communicate(input=catout)
  print "--- output ----"
  print grepout 
  print "--- error ----"
  print greperr 

if __name__ == "__main__":
  run()

Надеюсь, я достаточно ясно, спасибо за любую помощь.

Ответы [ 3 ]

6 голосов
/ 22 февраля 2011

Если вы делаете

from subprocess import Popen, PIPE
p1 = Popen(["cat"], stdout=PIPE, stdin=PIPE)

Вы должны сделать p1.communicate("Your Input to the p1"), и это будет течь через ТРУБУ.Stdin является входом процесса, и вы должны общаться только с этим.

Программа, которая дала абсолютно нормально, похоже, с этим проблем нет.

2 голосов
/ 20 августа 2013

Я предполагаю, что cat, grep являются просто примерами команд, в противном случае вы можете использовать чистое решение Python без подпроцессов, например ::1003 *

for line in simple.splitlines():
    if "line" in line:
       print(line)

Или, если вы хотите использовать grep:

from subprocess import Popen, PIPE

output = Popen(['grep', 'line'], stdin=PIPE, stdout=PIPE).communicate(simple)[0]
print output,

Вы можете передать вывод первой команды второй, не сохраняя ее сначала в строке:

from subprocess import Popen, PIPE
from threading import Thread

# start commands in parallel
first = Popen(first_command, stdin=PIPE, stdout=PIPE)
second = Popen(second_command, stdin=first.stdout, stdout=PIPE)
first.stdout.close() # notify `first` if `second` exits 
first.stdout = None # avoid I/O on it in `.communicate()`

# feed input to the first command
Thread(target=first.communicate, args=[simple]).start() # avoid blocking

# get output from the second command at the same time
output = second.communicate()[0]
print output,

Если вы не хотите хранить все данные ввода / вывода в памяти; вам могут понадобиться потоки (для чтения / записи в чанках без блокировки) или цикл выбора (работает в POSIX).

Если есть несколько команд, может быть более читабельным просто использовать оболочку напрямую, как это предложено @ Troels Folke , или использовать библиотеку, такую ​​как plumbum, которая скрывает все кровавые подробности эмуляции оболочки вручную .

1 голос
/ 20 августа 2013

Хм, а почему бы не смешать немного (ба) ш?: -)

from subprocess import Popen, PIPE
cproc = Popen('cat | grep line', stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True)
out, err = cproc.communicate("this line has the word line in it")

ВНИМАНИЕ, хотя:

  • Это работает только в системах, которые используют совместимую с Bourne Shell оболочку (как большинство * nix'es)

  • Usign shell = True, и ввод пользовательского ввода в командную строку является плохой идеей, если вы сначала не экранируете пользовательский ввод.Подробнее см. В документации по подпроцессам -> «Часто используемые аргументы».

  • Это некрасиво, непереносимо, непитонично и т. Д. ...

РЕДАКТИРОВАТЬ: Нет необходимости использовать cat, хотя, если все, что вы хотите сделать, это grep.Просто введите входные данные непосредственно в grep или, что еще лучше, используйте регулярные выражения python.

...