Python 2.7'de alt işlem çıktısı nasıl gizlenir


283

Ubuntu üzerinde eSpeak kullanıyorum ve bir mesaj yazıp söyleyen bir Python 2.7 betiği var:

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

eSpeak istenen sesleri üretir, ancak bazı hatalarla (ALSA lib ..., soket bağlantısı yok) kabukları keser, böylece daha önce basılanları kolayca okuyamam. Çıkış kodu 0.

Ne yazık ki ayrıntı düzeyini kapatmak için belgelenmiş bir seçenek yok, bu yüzden sadece görsel olarak susturmanın ve daha fazla etkileşim için açık kabuğu temiz tutmanın bir yolunu arıyorum.

Bunu nasıl yapabilirim?


sadece os.system ile görüşemez misiniz? ideal değil ama düşünmemeliyim yazdırmıyorum
Joran Beasley

@JoranBeasley: kabuk komutunu yeniden yönlendirmezseniz os.system () konsola yazdırılacaktır
jdi

hayır, os.system ('espeak' + text) bu davranışı yeniden oluşturur.
rypel

@ferkulat: os.systemSözdizimini de göstermek için cevabımı güncelledim . Rağmen sadece örnekleme içindir. Alt süreç ile sopa
jdi

2
2.7 olmayan spesifik sürüm: mükemmel çözüm için stackoverflow.com/questions/5495078/…subprocess.DEVNUL .
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

Yanıtlar:


426

Çıkışı DEVNULL'a yönlendir:

import os
import subprocess

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

Bu kabuk komutunu çalıştırmakla aynıdır:

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

50
Mikro düzgün seçtikleriniz: kullanabilirsiniz os.devnulleğer subprocess.DEVNULLmevcut değildir (<3.3), kullanım check_call()yerine call()sizin için ikili modda onun geri gönderilen kodu, açık dosyaları kontrol yoksa stdin/stdout/stderrkullanımı, os.system()önüne geçilmelidir, &>için çalışmıyor shUbuntu An üzerinde açık >/dev/null 2>&1kullanılabilir.
jfs

1
@JFSebastian: Öneriler için teşekkürler. Aslında kullanmak istedim os.devnullama yanlışlıkla yazdım . Ayrıca, callolası istisna check_callyükselecek yakalamıyorlar çünkü OP kullanımı ile yapışıyorum . Ve os.systemyönlendirme için, daha çok sadece alt süreç yaklaşımının etkili kullanımının ne olduğunun bir örneğiydi. Gerçekten ikinci bir öneri olarak değil.
jdi

13
Açtığınız FNULL'u kapatmanıza gerek yok mu?
Val

13
Sadece bir nota kullanabilirsiniz close_fds=Trueiçinde subprocess.callkapatmak için FNULLalt işlemi var sonra tanımlayıcı
ewino

7
@ewino: On close_fds=True, dosya tanımlayıcıları sonra kapatılır , fork()ancak daha önce çalıştırılabilir dosya çalıştırılmadan hemen önce alt süreçte execvp()kapatılır . akışlardan herhangi biri yeniden yönlendirilirse Windows'ta çalışmaz . üst işlemdeki dosyaları kapatmaz . close_fds=Trueclose_fds
jfs

89

İşte daha taşınabilir bir sürüm (sadece eğlence için, sizin durumunuzda gerekli değildir):

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

4
Bunun, DEVNULLgenel olarak sağlanmayan bir ürün ürettiğini unutmayın subprocess; açıldığından beri wbkullanılamaz stdin.
Reid

1
@Reid: 'r+b'bunun yerine ihtiyacınız varsa modu kullanabilirsiniz .
jfs

28

Kullanım subprocess.check_output(python 2.7'de yeni). Komut başarısız olursa, stdout'u bastırır ve bir istisna oluşturur. (Aslında stdout'un içeriğini döndürür, böylece isterseniz daha sonra programınızda kullanabilirsiniz.) Örnek:

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

Ayrıca stderr'ı aşağıdakilerle bastırabilirsiniz:

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

2.7'den önceki sürümler için

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

Burada, stderr'ı

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

Daha doğrusu, stdout'u döndürür. Bunu kullanmak istemeyebileceği gibi görmezden gelmenin yanı sıra harika.
Ciro Santilli 法轮功 冠状 :01 六四 事件 法轮功

Bunun daha basit olduğunu düşünüyorum. @StudentT CalledProcessError ile ilgili hataları ele almanız gerektiğini düşünüyorum. except subprocess.CalledProcessError as eve sonra e.codeveya kullanıne.output
Rodrigo E. Principe

21

Python3'ten itibaren artık devnull açmanıza gerek yok ve subprocess.DEVNULL çağırabilirsiniz .

Kodunuz şu şekilde güncellenir:

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

İşler! Buna ek olarak, takas stderrile stdoutbastırmak çıkışlarına (başka bir bağımsız değişken olarak ya da ekleme yapılması), yukarıdaki bir kodda olabilir. "Çıktılar" sorunun başlığı ve beni burada yönlendiren şey ... belki önemsiz, ama söz etmeye değer olduğunu düşündüm.
ThatsRightJack

-7

Bunun yerine neden commands.getoutput () kullanmıyorsunuz?

import commands

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

a) girişi atmaz, gereksiz yere bellekte biriktirir b) textiçinde tırnak varsa kırılır veya farklı bir karakter kodlaması kullanır veya bir komut satırı için çok büyüktür c) yalnızca Unix (Python 2'de)
jfs
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.