Cách ẩn đầu ra của quy trình con trong Python 2.7


283

Tôi đang sử dụng eSpeak trên Ubuntu và có tập lệnh Python 2.7 in và nói thông báo:

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

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

Thật không may, không có tùy chọn tài liệu nào để tắt tính dài dòng của nó, vì vậy tôi đang tìm cách chỉ im lặng trực quan và giữ cho vỏ mở sạch sẽ để tương tác hơn nữa.

Tôi có thể làm cái này như thế nào?


bạn có thể không chỉ gọi với os.system không? không lý tưởng nhưng không nên in tôi không nghĩ
Joran Beasley

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

không, os.system ('đặc biệt' + văn bản) tái tạo hành vi này.
rypel

@ferkulat: Tôi đã cập nhật câu trả lời của mình để hiển thị os.systemcú pháp. Mặc dù nó chỉ là để minh họa. Gắn bó với quy trình con
jdi

2
Phiên bản không cụ thể 2.7: stackoverflow.com/questions/5495078/ , cho phép subprocess.DEVNULgiải pháp hoàn hảo .
Ciro Santilli 郝海东 冠状 病 事件 法轮功

Câu trả lời:


426

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

import os
import subprocess

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

Nó thực sự giống như chạy lệnh shell này:

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

50
lựa chọn gọn gàng: bạn có thể sử dụng os.devnullnếu subprocess.DEVNULLkhô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ó, mở các tệp ở chế độ nhị phân stdin/stdout/stderr, os.system()không nên sử dụng Ubuntu , &>không hoạt động shtrên Ubuntu rõ ràng >/dev/null 2>&1có thể được sử dụng.
jfs

1
@JFSebastian: Cảm ơn những lời đề nghị. Tôi thực sự có ý định sử dụng os.devnullnhưng vô tình gõ nó ra. Ngoài ra, tôi vẫn gắn bó với việc sử dụng OP callvì họ không nắm bắt được ngoại lệ có thể xảy check_callra. Và đối với os.systemchuyển hướng, nó không chỉ là một minh họa về việc sử dụng hiệu quả phương pháp tiếp cận quy trình con đang làm gì. Không thực sự là một đề nghị thứ hai.
JDI

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

13
Chỉ cần một lưu ý, bạn có thể sử dụng close_fds=Truetrong subprocess.callđể đóng FNULLbộ mô tả sau khi tiến trình con tồn tại
ewino

7
@ewino: Bật close_fds=True, bộ mô tả tệp được đóng sau fork() nhưng trước đó execvp() , chúng được đóng trong quy trình con ngay trước khi thực thi được chạy. close_fds=Truesẽ không hoạt động trên Windows nếu bất kỳ luồng nào được chuyển hướng . close_fdskhông đóng các tập tin trong tiến trình cha .
jfs

89

Đây là phiên bản di động hơn (chỉ để giải trí, không 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

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

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

28

Sử dụng subprocess.check_output(mới trong python 2.7). Nó sẽ triệt tiêu thiết bị xuất chuẩn và đưa ra một ngoại lệ nếu lệnh thất bại. (Nó thực sự trả về nội dung của thiết bị xuất chuẩn, vì vậy bạn có thể sử dụng nó sau này trong chương trình của mình 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ể triệt tiêu stderr bằng:

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

Đối vớ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

Tại đây, bạn có thể triệt tiêu stderr với

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

Chính xác hơn, nó trả về thiết bị xuất chuẩn. Điều này thật tuyệt khi có thể muốn sử dụng nó bên cạnh việc có thể bỏ qua nó.
Ciro Santilli 郝海东 冠状 病 事件

Tôi nghĩ rằng điều này là đơn giản hơn. @StudentT Tôi nghĩ bạn nên xử lý lỗi với CalledProcessError. except subprocess.CalledProcessError as evà sau đó sử dụng e.codehoặce.output
Rodrigo E. Principe

21

Tính đến Python3 bạn không còn cần đến devnull mở và có thể gọi subprocess.DEVNULL .

Mã của bạn sẽ được cập nhật như vậy:

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

Làm! Ngoài ra, có thể trao đổi stderrvới stdoutmã ở trên (hoặc nối thêm làm đối số khác) để chặn đầu ra. "Đầu ra" là trong tiêu đề của câu hỏi và điều gì dẫn tôi đến đây ... có thể tầm thường, nhưng nghĩ rằng nó đáng được đề cập.
ThatsRightJack

-7

Tại sao không sử dụng lệnh.getoutput () thay thế?

import commands

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

a) nó không loại bỏ đầu vào, nó tích lũy nó vào bộ nhớ một cách không cần thiết b) nó bị hỏng nếu textcó dấu ngoặc kép trong đó hoặc sử dụng mã hóa ký tự khác hoặc quá lớn cho dòng lệnh c) nó chỉ là Unix (trên Python 2)
JFS
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.