Python 2.7でサブプロセスの出力を非表示にする方法


283

私はUbuntuでeSpeakを使用していて、メッセージを出力して話すPython 2.7スクリプトがあります。

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

eSpeakは目的のサウンドを生成しますが、いくつかのエラー(ALSA lib ...、ソケット接続なし)でシェルを乱雑にするため、以前に印刷されたものを簡単に読み取ることができません。終了コードは0です。

残念ながら、その冗長性をオフにする文書化されたオプションはないので、それを視覚的にのみ沈黙させ、オープンシェルをクリーンな状態に保ち、さらに対話する方法を探しています。

これどうやってするの?


それでは、os.systemで呼び出すことはできませんか?理想的ではないが印刷すべきではない
ジョランビーズリー

@JoranBeasley:シェルコマンドをリダイレクトしない限り、os.system()はコンソールに出力します
jdi

いいえ、os.system( 'espeak' + text)はこの動作を再現します。
リペル

@ferkulat:os.system構文も表示するように回答を更新しました。あくまでも例です。サブプロセスに固執する
-jdi

2
2.7固有ではないバージョン:stackoverflow.com/questions/5495078/…完全なsubprocess.DEVNULソリューションを可能にします。
Ciro Santilli郝海东冠状病六四事件法轮功

回答:


426

出力を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")

50
マイクロきちんとピック:あなたが使用できるos.devnull場合subprocess.DEVNULL(<3.3)が利用できない場合、使用check_call()の代わりに、call()あなたはその返されたコードを確認していない場合は、のためにバイナリモードで開いているファイルstdin/stdout/stderrの使用、os.system()落胆する必要がありますが、&>動作しませんshUbuntuのANに明示的>/dev/null 2>&1に使用できます。
jfs

1
@JFSebastian:提案をありがとう。実際に使用するos.devnullつもりでしたが、誤って入力してしまいました。また、call例外check_callが発生する可能性があることをキャッチしていないため、OPの使用に固執しています。os.systemリダイレクトについては、サブプロセスアプローチの効果的な使用が何をしているのかを示す単なる例でした。2番目の提案ではありません。
jdi

13
開いたFNULLを閉じる必要はありませんか?
Val

13
ただのメモ、サブプロセスが存在した後にclose_fds=Truein subprocess.callを使用してFNULL記述子を閉じることができます
ewino

7
@ewino:オンclose_fds=True、ファイル記述子がクローズされた後、 fork()しかし前に execvp()、すなわち、それらがで閉じられているばかりプロセスの前に実行ファイルが実行されます。close_fds=Trueいずれかのストリームがリダイレクトされる場合、Windowsでは機能しませんプロセスのclose_fdsファイルを閉じません。
jfs 2015

89

これはよりポータブルなバージョンです(お楽しみのために、あなたのケースでは必要ありません):

#!/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
これは、DEVNULLによって提供されるもののように、完全に一般的ではないを生成することに注意してくださいsubprocess。開いwbているのでには使えませんstdin
Reid

1
@Reid:'r+b'必要に応じてモードを使用できます。
jfs 14

28

使用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)

より正確には、標準出力を返します。これは無視したいだけでなく、使いたいかもしれないほど素晴らしいことです。
Ciro Santilli郝海东冠状病六四事件法轮功

これはもっと簡単だと思います。@StudentT CalledProcessErrorでエラーを処理する必要があると思います。またはor except subprocess.CalledProcessError as eを使用e.codee.output
Rodrigo E. Principe

21

Python3以降、devnullを開く必要がなくなり、subprocess.DEVNULLを呼び出すことができます。

あなたのコードはそのように更新されます:

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

動作します!さらに、上記のコードstderrと入れ替え てstdout(または別の引数として追加して)出力を抑制できます。「出力」は質問のタイトルにあり、ここで私を導いたものは...ささいなことかもしれませんが、言及する価値があると思いました。
ThatsRightJack

-7

代わりにcommands.getoutput()を使用しないのはなぜですか?

import commands

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

a)入力を破棄せず、不必要にメモリに蓄積しますb)text引用符が含まれている場合、または別の文字エンコーディングを使用している場合、またはコマンドラインには大きすぎる場合c)Unixのみです(Python 2の場合)
jfs 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.