2010-03-23 2 views
205

Я пытаюсь сделать системный вызов в Python и сохранить вывод в строку, которую я могу манипулировать в программе Python.Сохранять вывод подпроцесса. Вызов вызова в строке

#!/usr/bin/python 
import subprocess 
p2 = subprocess.Popen("ntpq -p") 

Я попробовал несколько вещей, в том числе некоторые из предложений здесь:

Retrieving the output of subprocess.call()

, но без удачи.

+1

Хорошо всегда публиковать фактический код, который вы запускали, и фактический трассировочный или неожиданный bahaviour для конкретных вопросов, подобных этому. Например, я не знаю, что вы пытались сделать, чтобы получить результат, и я подозреваю, что на самом деле вы так далеко не начали, - вы получили бы ошибку в том, что не нашли файл для '' ntpq -p " , что является другой частью проблемы, о которой вы просите. –

ответ

356

В Python 2.7 или Python 3

Вместо того, чтобы сделать Popen объект напрямую, вы можете использовать subprocess.check_output() function для хранения вывода команды в строке:

from subprocess import check_output 
out = check_output(["ntpq", "-p"]) 

В Python 2.4 -2.6

Используйте метод communicate.

import subprocess 
p = subprocess.Popen(["ntpq", "-p"], stdout=subprocess.PIPE) 
out, err = p.communicate() 

out - это то, что вы хотите.

Важное примечание о других ответах

Обратите внимание, как я перешел в команду. Пример "ntpq -p" вызывает другое дело. Поскольку Popen не вызывает оболочку, вы должны использовать список команд и опций - ["ntpq", "-p"].

+2

В этом случае python ожидает завершения этого системного вызова? Или нужно явно вызвать функцию wait/waitpid? – NoneType

+5

@NoneType, 'Popen.communicate' не возвращается, пока процесс не завершится. –

+8

, если вы хотите получить поток ошибок, добавьте stderr: 'p = subprocess.Popen ([" ntpq "," -p "], stdout = subprocess.PIPE, stderr = subprocess.PIPE) ' – Tim

32

Это работало для меня перенаправляет стандартный вывод (STDERR могут быть обработаны аналогичным образом):

from subprocess import Popen, PIPE 
pipe = Popen(path, stdout=PIPE) 
text = pipe.communicate()[0] 

Если это не работает для вас, пожалуйста, точно указать проблемы, которую вы имеете.

+3

Это создает какой-то странный объект. Когда я конвертирую его в строку, он избегает пробелов, таких как '\ n'. –

19

Предполагая, что pwd это просто пример, это то, как вы можете это сделать:

import subprocess 

p = subprocess.Popen("pwd", stdout=subprocess.PIPE) 
result = p.communicate()[0] 
print result 

Смотрите subprocess documentation для another example и получения дополнительной информации.

4
import os 
list = os.popen('pwd').read() 

В этом случае у вас будет только один элемент в списке.

+5

'os.popen' устарел в пользу модуля' subprocess'. –

+2

Это было очень полезно для администратора на старом ящике с использованием серии 2.2.X Python. –

15

subprocess.Popen: http://docs.python.org/2/library/subprocess.html#subprocess.Popen

import subprocess 

command = "ntpq -p" # the shell command 
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, shell=True) 

#Launch the shell command: 
output = process.communicate() 

print output[0] 

В конструкторе POPEN, если оболочка является Истинной, вы должны передать команду в виде строки, а не как последовательность. В противном случае, просто разделить команду в список:

command = ["ntpq", "-p"] # the shell command 
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None) 

Если вам нужно прочитать также стандартную ошибку, в инициализации POPEN, вы можете установить STDERR к подпроцесс.ТРУБА или subprocess.STDOUT:

import subprocess 

command = "ntpq -p" # the shell command 
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 

#Launch the shell command: 
output, error = process.communicate() 
+0

+1 для аргумента оболочки –

3

я написал небольшую функцию на основе других ответов здесь:

def pexec(*args): 
    return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0].rstrip() 

Использование:

changeset = pexec('hg','id','--id') 
branch = pexec('hg','id','--branch') 
revnum = pexec('hg','id','--num') 
print('%s : %s (%s)' % (revnum, changeset, branch)) 
10

Это отлично работает для меня :

import subprocess 
try: 
    #prints results and merges stdout and std 
    result = subprocess.check_output("echo %USERNAME%", stderr=subprocess.STDOUT, shell=True) 
    print result 
    #causes error and merges stdout and stderr 
    result = subprocess.check_output("copy testfds", stderr=subprocess.STDOUT, shell=True) 
except subprocess.CalledProcessError, ex: # error code <> 0 
    print "--------error------" 
    print ex.cmd 
    print ex.message 
    print ex.returncode 
    print ex.output # contains stdout and stderr together 
3

Это было идеально для меня. Вы получите код возврата, stdout и stderr в кортеже.

from subprocess import Popen, PIPE 

def console(cmd): 
    p = Popen(cmd, shell=True, stdout=PIPE) 
    out, err = p.communicate() 
    return (p.returncode, out, err) 

Для примера:

result = console('ls -l') 
print 'returncode: %s' % result[0] 
print 'output: %s' % result[1] 
print 'error: %s' % result[2] 
7

для Python 2.7+ идиоматического Ответ заключается в использовании subprocess.check_output()

Следует также отметить обработку аргументов при вызове подпроцесса, как это может немного запутаться ....

Если args - единственная команда без собственных аргументов (или у вас есть shell=True), это может быть строка. В противном случае это должен быть список.

, например ... для вызова команды ls, это хорошо:

from subprocess import check_call 
check_call('ls') 

так это:

from subprocess import check_call 
check_call(['ls',]) 

Однако, если вы хотите, чтобы передать некоторые аргументы в команде оболочки , вы не можете это сделать:

from subprocess import check_call 
check_call('ls -al') 

инов TEAD, вы должны передать его в виде списка:

from subprocess import check_call 
check_call(['ls', '-al']) 

функция shlex.split() иногда может быть полезно разбить строку в оболочке, как синтаксис, прежде чем создавать подпроцессы ... как это:

from subprocess import check_call 
import shlex 
check_call(shlex.split('ls -al')) 
+0

Пять лет спустя этот вопрос по-прежнему вызывает много любви. Спасибо за обновление 2.7+, Кори! – Mark

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