2012-06-29 9 views
194

Tôi đang sử dụng eSpeak trên Ubuntu và có một Python 2.7 kịch bản in và nói một thông điệp:Làm thế nào để che giấu sản lượng của tiến trình con bằng Python 2.7

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

eSpeak tạo ra âm thanh mong muốn, nhưng clutters vỏ với một số lỗi (ALSA lib ..., không có ổ cắm kết nối) vì vậy tôi không thể dễ dàng đọc những gì đã được in trước đó. Mã thoát là 0.

Rất tiếc, không có tùy chọn được ghi tài liệu để tắt tính từ, vì vậy tôi đang tìm cách chỉ im lặng trực quan và giữ cho vỏ mở luôn sạch sẽ để tương tác hơn nữa.

Làm thế nào tôi có thể làm điều này?

+0

bạn có thể không chỉ gọi với os.system sau đó không? không lý tưởng nhưng không in tôi không nghĩ rằng –

+0

@JoranBeasley: os.system() sẽ in ra bàn điều khiển trừ khi bạn chuyển hướng lệnh shell – jdi

+0

no, os.system ('espeak' + text) tái tạo hành vi này. – ferkulat

Trả lời

292

Chuyển hướng đầu ra để DEVNULL:

import os 
import subprocess 

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

Đó là một cách hiệu quả giống như chạy lệnh shell này:

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

vi chọn gọn gàng: bạn có thể sử dụng 'os.devnull' nếu' subprocess.DEVNULL' không có sẵn (<3.3), sử dụng 'check_call()' thay vì 'call()' nếu bạn không kiểm tra mã trả về của nó, các tệp mở ở chế độ nhị phân cho 'stdin/stdout/stderr', nên sử dụng' os.system() ',' &> 'không hoạt động đối với' sh' trên Ubuntu một '>/dev/null rõ ràng 2 > & 1' có thể được sử dụng. – jfs

+0

@ J.F.Sebastian: Cảm ơn các đề xuất. Tôi thực sự có nghĩa là để sử dụng 'os.devnull' nhưng vô tình gõ nó ra. Ngoài ra, tôi đang gắn bó với OP sử dụng 'call' vì họ không bắt được ngoại lệ có thể' check_call' sẽ tăng lên. Và đối với chuyển hướng 'os.system', nó chỉ là một minh hoạ cho việc sử dụng hiệu quả phương thức của tiến trình con đang thực hiện. Không thực sự là một gợi ý thứ hai. – jdi

+10

Bạn không cần phải đóng FNULL mà bạn đã mở? – Val

64

Dưới đây là một phiên bản di động hơn (chỉ để cho vui, nó không phải là cần thiết trong trường hợp của bạn):

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

Lưu ý rằng điều này tạo ra một 'DEVNULL' mà không phải là hoàn toàn chung chung, giống như cái được cung cấp bởi' subprocess'; kể từ khi nó mở 'wb' nó không thể được sử dụng cho' stdin'. – Reid

+0

@Reid: bạn có thể sử dụng chế độ '' r + b'' nếu cần. – jfs

-5

Tại sao không sử dụng commands.getoutput()?

import commands 

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

a) nó không loại bỏ đầu vào, nó tích lũy nó trong bộ nhớ không cần thiết b) nó ngắt nếu 'text' có dấu ngoặc kép trong nó, hoặc sử dụng mã hóa ký tự khác hoặc quá lớn đối với dòng lệnh c) chỉ là Unix (trên Python 2) – jfs

18

Sử dụng subprocess.check_output (mới trong python 2.7). Nó sẽ ngăn chặn stdout và đưa ra một ngoại lệ nếu lệnh không thành công. (Nó thực sự trả về nội dung của stdout, vì vậy bạn có thể sử dụng sau này trong chương trình của bạn nếu bạn muốn.) Ví dụ:

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

Bạn cũng có thể ngăn chặn stderr với:

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

Đối sớm hơn 2,7 , sử dụng

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

Ở đây, bạn có thể ngăn chặn stderr với

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

Chính xác hơn, nó trả về giá trị chuẩn. Đó là tuyệt vời như có thể muốn sử dụng nó cũng như bên cạnh việc có thể bỏ qua nó. –

+0

Tuy nhiên, nó không che giấu các lỗi tiêu chuẩn. – SmallChess

+0

Tôi nghĩ điều này đơn giản hơn. @StudentT Tôi nghĩ bạn nên xử lý lỗi với CalledProcessError. 'ngoại trừ subprocess.CalledProcessError như e' và sau đó sử dụng' e.code' hoặc 'e.output' –

0

nếu bạn tình cờ sử dụng mô-đun phụ trong cửa sổ (không cụ thể cho câu hỏi này nhưng khớp với tiêu đề) với python 2.7x và CHỈ là lỗi bạn muốn chặn (cụ thể cho câu hỏi này), bạn có thể làm điều gì đó như này:

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

bạn sẽ có thể kiểm tra bằng cách sử dụng mã ở trên vào hệ thống của bạn, nhưng nếu xảy ra 127.0.0.2 để tồn tại trong bảng arp của bạn, bạn chỉ có thể chọn một ip mà không có một nic liên quan nó.

+1

Điều đó không loại bỏ các lỗi. Nó chuyển hướng stderr thành stdout, do đó, 'output' có đầu ra và lỗi sai, có lẽ không phải là thứ mong muốn. –