2010-02-22 4 views
7

У меня есть команда, которая отлично работает в командной строке. У этого есть много аргументов, таких как cmd --thing foo --stuff bar -a b input outputИспользование python для запуска других программ

Я хочу запустить это из python и блокировать его до завершения. Поскольку сценарий печатает вещи до stdout и stderr, я хочу, чтобы это было немедленно показано пользователю.

Что такое правильный модуль для этого?

Я пробовал:


import commands 
output = commands.getoutput("cmd --thing foo --stuff bar -a b input output") 
print output 

это прекрасно работает, кроме stdout не не возвращается до конца.


import os 
os.system("cmd --thing foo --stuff bar -a b input output") 

это печатает все выходные, когда CMD фактически закончена.


import subprocess 
subprocess.call(["cmd", "--thing foo", "--stuff bar", "-a b", "input", "output"]) 

это не передать параметры правильно как-то (я не смог найти точную проблему, но cmd отклоняет мой вход). Если я ставлю echo в качестве первого параметра, он выдает команду, которая отлично работает, когда я вставляю ее непосредственно в терминал.


import subprocess 
subprocess.call("cmd --thing foo --stuff bar -a b input output") 

точно так же, как описано выше.

+0

Исправлено. Спасибо. –

ответ

3

Если вам не нужно обрабатывать выход в коде, только чтобы показать его пользователь как это происходит (это не ясно из вашего Q, и кажется, что путь от своего собственного личного ответа), проще всего:

rc = subprocess.call(
    ["cmd", "--thing", "foo", "--stuff", "bar", 
    "-a", "b", "input", "output"]) 
print "Return code was", rc 

т.е. просто избегать использования труб - пусть стандартный вывод и стандартный поток ошибок просто показать на терминал. Это должно избегать любых проблем с буферизацией. Как только вы помещаете трубы в изображение, буферизация обычно - это проблема, если вы хотите показать вывод, как это происходит (я удивлен, что ваш автоответчик не имеет этой проблемы ;-).

Для обоих показывая и захвата, кстати, я всегда рекомендую pexpectwexpect на Windows) точно работать вокруг проблемы буферизации.

+0

Как всегда, спасибо Алекс. Кажется, что 'subprocess.call()' буферизует вывод другой программы, что НЕ является поведением, которое обычно происходит на терминале для этой программы. Должен ли я просто выполнить proc: subprocess.Popen', а затем цикл for на proc.stdout, выводящий результат? –

+1

@Paul, это не «подпроцесс», делающий буферизацию, это делает его исполняющей библиотекой C в другой программе, когда она замечает, что это будет канал, а не терминал (то, что вы наблюдаете, удивительно, поскольку stdout _is_ переходит на терминал, поэтому буферизация не должно происходить). 'pexpect' использует псевдотерминалы для обмана библиотек среды выполнения другой программы и поэтому останавливает их от буферизации (' wexpect' в Windows). Я рекомендовал им много раз много раз искать другие ответы для своих URL-адресов. –

7

Вы должны указывать каждое поле отдельно, т.е. разделите параметры из своих аргументов.

import subprocess 
output = subprocess.call(["cmd", "--thing", "foo", "--stuff", "bar", "-a", "b", "input", "output"]) 

иначе вы эффективно работает ЦМД как этот

$ cmd --thing\ foo --stuff\ bar -a\ b input output 

Чтобы получить выход в трубу нужно вызвать ее немного по-другому

import subprocess 
output = subprocess.Popen(["cmd", "--thing", "foo", "--stuff", "bar", "-a", "b", "input", "output"],stdout=subprocess.PIPE) 
output.stdout # <open file '<fdopen>', mode 'rb'> 
+0

'subprocess', похоже, не печатает вывод по мере его возврата. Могу ли я это сделать? –

+0

@Paul Tarjan: Это дублированный вопрос. Пожалуйста, найдите '' [python] подпроцесс "', и вы получите десятки ответов на этот вопрос. –

2

Не было commands.getstatusoutput () Работа? Он вернет ваш статус сразу.

+1

Это так, но следует предупредить, что это только POSIX (без Windows). – jathanism

1

Коллега только что показала мне это:

import os 
import sys 
for line in os.popen("cmd --thing foo --stuff bar -a b input output", "r"): 
    print line 
    sys.stdout.flush() 

и он работает :)

+2

Вы должны использовать 'subprocess', предпочитая' popen'. С одной стороны, это избавляет вас от беспокойства об экранировании параметров. –

+1

Другая причина: поскольку Python 2.6 'os.popen()' классифицируется как устаревший в пользу 'subprocess' (см. Http://docs.python.org/library/os. HTML # os.popen). –

Смежные вопросы