2012-06-29 9 views
194

Używam eSpeak na Ubuntu i mieć skrypt Pythona 2.7, która drukuje i mówi komunikat:Jak ukryć wyjście podproces w Pythonie 2.7

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

eSpeak produkuje żądane dźwięki, ale zaśmiecanie powłoce z niektóre błędy (ALSA lib ..., brak połączenia z gniazdem), więc nie mogę łatwo odczytać tego, co zostało wydrukowane wcześniej. Kod zakończenia to 0.

Niestety nie ma udokumentowanej opcji wyłączenia jej gadatliwości, więc szukam sposobu, aby wizualnie ją wyciszyć i zachować otwartą powłokę w czystości w celu dalszej interakcji.

Jak mogę to zrobić?

+0

czy nie można po prostu połączyć się z systemem os.system? nie jest idealny, ale nie powinien drukować Nie sądzę, że –

+0

@JoranBeasley: os.system() będzie drukować na konsoli, chyba że przekierujesz polecenie powłoki – jdi

+0

nie, os.system ("espeak" + tekst) odtwarza to zachowanie. – ferkulat

Odpowiedz

292

przekierować wyjście do DEVNULL:

import os 
import subprocess 

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

To skutecznie takie same jak działa to polecenie powłoki:

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

drobnostki: możesz użyć 'os.devnull' jeśli' subprocess.DEVNULL' nie jest dostępny (<3.3), użyj 'check_call()' zamiast 'call()' jeśli nie zaznaczysz zwróconego kodu, otwierać pliki w trybie binarnym dla 'stdin/stdout/stderr', należy odradzać użycie' os.system() ',' &> 'nie działa dla' sh' na Ubuntu jawne '>/dev/null 2 > & 1' może być użyte. – jfs

+0

@ J.F.Sebastian: Dzięki za sugestie. Właściwie zamierzałem użyć 'os.devnull', ale przypadkowo go wypisałem. Ponadto, trzymam się OP używania 'call', ponieważ nie wychwytują możliwego wyjątku' check_call' podniosłoby. I dla przekierowania 'os.system', było to tylko ilustracją tego, co robi efektywne wykorzystanie podejścia podprocesowego. Nie tak naprawdę jako druga sugestia. – jdi

+10

Nie musisz zamykać FNULL, który otworzyłeś? – Val

64

Oto bardziej przenośna wersja (tylko dla zabawy, nie jest konieczne Twój przypadek):

#!/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

Zauważ, że tworzy to 'DEVNULL', który nie jest w pełni ogólny, jak ten dostarczony przez' podproces '; ponieważ jest otwarty 'wb', nie może być użyty dla' stdin'. – Reid

+0

@Reid: możesz użyć trybu "r + b", jeśli potrzebujesz tego. – jfs

-5

Dlaczego zamiast tego należy użyć commands.getoutput()?

import commands 

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

a) nie odrzuca danych wejściowych, niepotrzebnie gromadzi je w pamięci b) zrywa, gdy "tekst" ma w cudzysłowie lub używa innego kodowania znaków lub jest za duży dla wiersza poleceń c) jest to tylko system Unix (na Pythonie 2) – jfs

18

Użyj subprocess.check_output (nowy w python 2.7). Spowoduje to wyłączenie standardowego wyjścia i zgłoszenie wyjątku, jeśli polecenie się nie powiedzie. (To faktycznie zwraca zawartość stdout, więc można użyć później w programie, jeśli chcesz.) Przykład:

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

Można również tłumić stderr z:

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

Dla wcześniej niż 2,7 użyj

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

Tutaj można stłumić stderr z

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

Dokładniej, zwraca stdout. Co jest świetne, ponieważ może chcieć z niego korzystać, a także być w stanie to zignorować. –

+0

Jednak nie maskuje błędów standardowych. – SmallChess

+0

Myślę, że to jest bardziej proste. @StudentT Myślę, że powinieneś obsługiwać błędy z CalledProcessError. 'z wyjątkiem podprocesu.CalledProcessError jako e', a następnie użyj' e.code' lub 'e.output' –

0

jeśli używasz modułu podprocesowego w oknach (nie jest to specyficzne dla tego pytania, ale pasuje do tytułu) z pythonem 2.7x i to TYLKO błędy, które chcesz stłumić (specyficzne dla tego pytania), możesz zrobić coś takiego to:

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

powinieneś być w stanie przetestować stosując powyższy kod w systemie, ale jeśli 127.0.0.2 stanie istnieć w swojej tablicy aRP można po prostu wybrać adres IP, który nie ma NIC związanego z to.

+1

To nie tłumi błędów. Przekierowuje stderr na stdout, więc 'output' powoduje zmniejszenie wydajności i błędów, co prawdopodobnie nie jest pożądane. –