Подавить вывод в вызовах Python исполняемых файлов

У меня есть бинарный файл A который генерирует вывод при вызове. Если я вызываю его из оболочки Bash, большая часть вывода подавляется A > /dev/null, Весь вывод подавляется A &> /dev/null

У меня есть скрипт на Python с именем B что нужно позвонить A, Я хочу иметь возможность генерировать вывод из Bподавляя все выходные данные A,

Изнутри B, Я пробовал os.system('A'), os.system('A > /dev/null'), а также os.system('A &> /dev/null'), os.execvp('...')и т. д., но ни один из них не подавляет весь вывод A.

Я мог бежать B &> /dev/null, но это подавляет все Bвыход тоже, и я не хочу этого.

У кого-нибудь есть предложения?

9 ответов

Решение

Если у вас есть Python 2.4, вы можете использовать модуль подпроцесса:

>>> import subprocess
>>> s = subprocess.Popen(['cowsay', 'hello'], \
      stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0]
>>> print s
 _______ 
< hello >
 ------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
import os
import subprocess

command = ["executable", "argument_1", "argument_2"]

with open(os.devnull, "w") as fnull:
    result = subprocess.call(command, stdout = fnull, stderr = fnull)

Если команда не имеет аргументов, вы можете просто указать ее в виде простой строки.

Если ваша команда опирается на такие функции оболочки, как подстановочные знаки, каналы или переменные окружения, вам нужно предоставить всю команду в виде строки, а также указать shell = True, Этого следует избегать, так как это представляет угрозу безопасности, если содержимое строки не проходит тщательную проверку.

В Python 3.3 и выше, subprocess поддерживает опцию для перенаправления на/dev/null, Использовать его при звонке .Popen а друзья уточни stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, в качестве ключевых аргументов.

Таким образом, ответ DNS, переписанный для Python 3.3+, становится

import subprocess
command = ["executable", "argument_1", "argument_2"]
result = subprocess.call(command,
                         stdout=subprocess.DEVNULL,
                         stderr=subprocess.DEVNULL)

Из документации:

subprocess.DEVNULL¶

Специальное значение, которое может использоваться в качестве аргумента stdin, stdout или stderr для Popen и указывает, что будет использоваться специальный файл os.devnull.

Новое в версии 3.3.

Для Python 3.0 до 3.2 вы должны вручную открыть нулевое устройство, используя open(os.devnull), как ДНС написал.

Если ваша поисковая система привела вас к этому старому вопросу (как и я), помните, что использование PIPE может привести к тупикам. Действительно, поскольку каналы буферизуются, вы можете записать определенное количество байтов в канал, даже если никто его не читает. Однако размер буфера конечен. И, следовательно, если ваша программа A имеет выход больше буфера, A будет заблокирован при записи, в то время как вызывающая программа B ожидает завершения A. Но нет, в данном конкретном случае... см. Комментарии ниже.

Тем не менее, я рекомендую использовать решение Devin Jeanpierre и DNS.

Как упоминается в документации os.system(), при открытии подпроцесса используйте модуль подпроцесса и, если хотите, установите stdout=open(os.devnull, 'w') (и, возможно, то же самое для stderr).

Я знаю, что уже поздно в игре, но почему бы просто не перенаправить вывод в /dev/null из os.system? Например:

tgt_file = "./bogus.txt"
os.sytem("d2u '%s' &> /dev/null" % tgt_file)

Кажется, это работает в тех случаях, когда вы не хотите иметь дело с подпроцессом.STDOUT.

Если вы не хотите ждать завершения команды, такой как запуск задачи резервного копирования, другой вариант - пропустить ее через bash, что позволяет перенаправлению работать нормально.

Например, запуск звукового файла с помощью aplay:

import os

def PlaySound(filename):
    command = 'bash -c "aplay %s &> /dev/null &"' % (filename)
    os.system(command)

Таким образом, я могу создать новый процесс, не дожидаясь его завершения, и остановить его печать на терминале. Единственный улов - это то, что он будет загружать экземпляр bash, а также процесс, который вы запускаете, обеспечивая небольшую нагрузку.

Если вам нужно просто захватить STDOUT, не делает ли это присвоение переменной? Например:

megabyte=''
# Create a 1 MiB string of NULL characters.
for i in range(1048576):
    megabyte += '\0'
fh=open('zero.bin','w')
# Write an 8 GiB file.
for i in range(8192):
    print(i)
    # Suppress output of 'write()' by assigning to a variable.
    discard=fh.write(megabyte)
fh.close()

Я создавал большой заполненный нулями файл с нулевым свободным пространством на моем жестком диске и обнаружил, что каждый вызов handle.write(string) выплевывает количество записанных байтов. Присвоение этого переменной исключено.

Я использую:

call(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE)

где команда это строка команды + аргументы

Чтобы это работало, вы должны импортировать подпроцесс

Другие вопросы по тегам