2012-06-29 2 views
194

Я использую озвучки на Ubuntu и есть Python 2.7 скрипт, который печатает и говорит сообщение:Как скрыть выход подпроцесс в Python 2.7

import subprocess 
text = 'Hello World.' 
print text 
subprocess.call(['espeak', text]) 

озвучки производит желаемые звуки, но загромождает шелл некоторые ошибки (ALSA lib ..., no socket connect), поэтому я не могу легко прочитать то, что было напечатано ранее. Код выхода равен 0.

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

Как я могу это сделать?

+0

Не могли бы вы просто позвонить с os.system? не идеален, но не должен печатать, я не думаю, что –

+0

@JoranBeasley: os.system() будет печатать на консоль, если вы не перенаправите команду оболочки – jdi

+0

no, os.system ('espeak' + text) воспроизводит это поведение. – ferkulat

ответ

292

Перенаправить вывод DEVNULL:

import os 
import subprocess 

FNULL = open(os.devnull, 'w') 
retcode = subprocess.call(['echo', 'foo'], stdout=FNULL, stderr=subprocess.STDOUT) 

Это фактически то же самое, как работает эта команда оболочки:

retcode = os.system("echo 'foo' &> /dev/null") 
+40

микро-опционы: вы можете использовать 'os.devnull', если' subprocess.DEVNULL' недоступен (<3.3), используйте 'check_call()' вместо 'call()', если вы не проверяете его возвращенный код, открытые файлы в двоичном режиме для 'stdin/stdout/stderr', использование' os.system() 'должно быть обескуражено,' &> 'не работает для' sh' на Ubuntu явным '>/dev/null 2 > & 1'. – jfs

+0

@ J.F.Sebastian: Спасибо за предложения. Я действительно хотел использовать 'os.devnull', но случайно набрал его. Кроме того, я придерживаюсь использования OPs 'call', поскольку они не улавливают возможное исключение, которое« check_call »будет поднимать. И для перенаправления 'os.system' это было скорее всего лишь иллюстрацией того, что делает эффективное использование подпроцессного подхода. На самом деле это не второе предложение. – jdi

+10

Вам не нужно закрывать FNULL, который вы открыли? – Val

64

Вот более портативная версия (только для удовольствия, он не является необходимым в ваш случай):

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
from subprocess import Popen, PIPE, STDOUT 

try: 
    from subprocess import DEVNULL # py3k 
except ImportError: 
    import os 
    DEVNULL = open(os.devnull, 'wb') 

text = u"René Descartes" 
p = Popen(['espeak', '-b', '1'], stdin=PIPE, stdout=DEVNULL, stderr=STDOUT) 
p.communicate(text.encode('utf-8')) 
assert p.returncode == 0 # use appropriate for your program error handling here 
+2

Обратите внимание, что это создает 'DEVNULL', который не является полностью общим, как тот, который предоставляется подпроцессом; поскольку он открыт 'wb', он не может использоваться для' stdin'. – Reid

+0

@Reid: вы можете использовать режим 'r + b'', если вам это нужно. – jfs

-5

Почему бы не использовать command.getoutput() вместо этого?

import commands 

text = "Mario Balotelli" 
output = 'espeak "%s"' % text 
print text 
a = commands.getoutput(output) 
+0

a) он не отбрасывает ввод, он аккумулирует его в памяти без необходимости; б) он ломается, если 'text' имеет в нем кавычки или использует различную кодировку символов или слишком велико для командной строки c) это только Unix (на Python 2) – jfs

18

Используйте subprocess.check_output (новый в Python 2.7). Он отключит stdout и вызовет исключение, если команда завершится с ошибкой. (Это фактически возвращает содержимое стандартного вывода, так что вы можете использовать это позже в вашей программе, если вы хотите.) Пример:

import subprocess 
try: 
    subprocess.check_output(['espeak', text]) 
except subprocess.CalledProcessError: 
    # Do something 

Вы также можете подавить STDERR с:

subprocess.check_output(["espeak", text], stderr=subprocess.STDOUT) 

Для ранее, чем 2.7 используйте

import os 
import subprocess 
with open(os.devnull, 'w') as FNULL: 
    try: 
     subprocess._check_call(['espeak', text], stdout=FNULL) 
    except subprocess.CalledProcessError: 
     # Do something 

Здесь вы можете подавить STDERR с

 subprocess._check_call(['espeak', text], stdout=FNULL, stderr=FNULL) 
+0

Точнее, он возвращает stdout. Это замечательно, так как может хотеть использовать его, а также быть способным игнорировать его. –

+0

Однако он не маскирует стандартные ошибки. – SmallChess

+0

Я думаю, что это более прямолинейно. @StudentT Я думаю, что вы должны обрабатывать ошибки с помощью CalledProcessError. 'except subprocess.CalledProcessError as e', а затем использовать' e.code' или 'e.output' –

0

, если вы используете модуль подпроцесса в окнах (не конкретно для этого вопроса, но соответствует заголовку) с python 2.7x, и это ТОЛЬКО ошибки, которые вы хотите подавить (специфичные для этого вопроса), вы можете сделать что-то вроде это:

output = subprocess.check_output(["arp", "-a", "-N", "127.0.0.2"], stderr=subprocess.STDOUT)

вы должны быть в состоянии проверить, используя код, указанный выше в вашей системе, но если 127.0.0.2 происходит существовать в вашей агр таблице вы можете просто выбрать IP, который не имеет сетевой адаптер, связанный с Это.

+1

Это не подавляет ошибки. Он перенаправляет stderr на stdout, поэтому 'output' отображает вывод и ошибки, что, вероятно, не является желательным. –