Подавить вывод в вызовах Python исполняемых файлов - PullRequest
44 голосов
/ 31 марта 2009

У меня есть двоичный файл с именем 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 ]

102 голосов
/ 31 марта 2009
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. Этого следует избегать, так как это представляет угрозу безопасности, если содержимое строки не проходит тщательную проверку.

57 голосов
/ 31 марта 2009

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

>>> import subprocess
>>> s = subprocess.Popen(['cowsay', 'hello'], \
      stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0]
>>> print s
 _______ 
< hello >
 ------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
21 голосов
/ 29 сентября 2011

В 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), как пишет DNS.

12 голосов
/ 28 апреля 2010

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

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

8 голосов
/ 31 марта 2009

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

1 голос
/ 23 июня 2009

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

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

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

0 голосов
/ 22 июня 2013

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

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

import os

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

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

0 голосов
/ 18 июня 2011

Если вам нужно просто захватить 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) выплевывает количество записанных байтов. Присвоение этого значения исключаемому выводу.

0 голосов
/ 27 апреля 2011

Я использую:

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

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

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

...