Подпроцесс python не записывает вывод

У меня есть следующий фрагмент кода в виде скрипта Python. Я получаю правильные выходные файлы задания без ошибок. Однако файлы журнала stdoutsubprocess (например, COSMOSIS_output_XXX.txt и т. д.) не хранят ожидаемые журналы времени выполнения. Вместо этого эти файлы имеют <_io.TextIOWrapper name=9 encoding='UTF-8'> как единственный вывод, записанный в файлах. Что я делаю неправильно?

import subprocess
from subprocess import Popen
jobname = "cosmosis"
arg2 = "output.filename = "
Vector = (
    " " + ini + " " + arg2 + COSMOSIS_PATH + os.path.splitext(ini)[0] + ".txt"
)                                                                                                                                                                                               

job3 = subprocess.Popen(
    ["cosmosis" + Vector],
    shell=True,
    text=True,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
)

file = open("%sCOSMOSIS_output_%s.txt" % (ERROR_PATH, ini), "a")
sys.stdout = file
print(job3.stdout)
file_e = open("%sCOSMOSIS_output_ERROR_%s.txt" % (ERROR_PATH, ini), "a")
sys.stdout = file_e
print(job3.stderr)
try:
    outs, errs = job3.communicate(timeout=2000)                                                                                                                                      
except TimeoutExpired:
    outs, errs = job3.communicate()
    job3.kill()
file.close()
file_e.close()
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
289
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Прежде всего, вы просто открываете файл, вы ничего из него не читаете, вы нигде не храните информацию о файле, поэтому он просто создаст этот <_io.TextIOWrapper name=9 encoding='UTF-8'>, который очень легко воспроизвести:

file = open("testtextf.txt","a")
print(file)

Вы должны прочитать это как-то, например, с помощью .read():

data = file.read()

Также я не рекомендую использовать «открыть», если вы не хотите иметь дело с файлами, оставленными открытыми, если что-то пойдет не так между строками, прежде чем вы снова закроете его.

Я настоятельно рекомендую вместо этого использовать «с открытым».

Спасибо. Не могли бы вы предоставить полный воспроизводимый фрагмент?

Ayan Mitra 28.11.2022 06:40

Хорошо, следующий фрагмент является достаточным решением вопроса, опубликованного выше.

with open("%sCOSMOSIS_output_%s.txt" % (ERROR_PATH, ini), "wb") as file, open("%sCOSMOSIS_output_ERROR_%s.txt" % (ERROR_PATH, ini), "wb") as file_e:
    job3 = subprocess.Popen(
        ["cosmosis" + Vector],
        shell=True,
        text=True,
        stdout=file,
        stderr=file_e,
    )

Передача списка строк с помощью shell=True работает в Windows, но не на других платформах (ну, вы можете заставить это работать, но вы должны знать, что делаете). Вероятно, избегайте этого сочетания.

tripleee 01.12.2022 18:16

Я не работаю с окнами. Это очень хорошо работает в Linux.

Ayan Mitra 02.12.2022 19:17

Квадратные скобки вокруг строки не нужны и несколько вводят в заблуждение. Вы должны передать только строку с shell=True или правильно разделенный список токенов без (попробуйте shlex.split() или просто не склеивайте части вместе). Смотрите также Фактическое значение shell=True в подпроцессе

tripleee 02.12.2022 21:59

@AyanMitra Если вы не хотите, чтобы этот ответ оставался здесь, вы можете удалить его самостоятельно, используя ссылку «Удалить» выше.

sideshowbarker 02.12.2022 23:19
Ответ принят как подходящий

Передача списка в качестве первого аргумента с shell=True зависит от системы. Я предполагаю, что вы действительно имеете в виду

with open("%sCOSMOSIS_output_%s.txt" % (ERROR_PATH, ini), "ab") as file,
        open("%sCOSMOSIS_output_ERROR_%s.txt" % (ERROR_PATH, ini), "a") as file_e:
    try:
        job3 = subprocess.run(
            ["cosmosis", ini, arg2, COSMOSIS_PATH, os.path.splitext(ini)[0] + ".txt"],
            stdout=file, stderr=file_e, check=True,
            timeout=2000)
    except TimeoutExpired:
        pass

job3.stdout или job3.stderr не могут содержать что-либо, потому что мы перенаправили их в файлы. (Мы открываем дескрипторы файлов в двоичном режиме, поэтому нам не нужно указывать кодировку текста.) Процесс также не может вернуть полезный результат, если он был уничтожен по тайм-ауту, и, очевидно, нет необходимости его уничтожать. когда его уже убили.

Как уже сказано в документации subprocess, по возможности следует предпочесть subprocess.run или одну из устаревших высокоуровневых оболочек вместо Popen. Возможно, см. также Фактическое значение shell=True в подпроцессе, что также объясняет, почему вы хотите избегать использования оболочки, когда это возможно.

С другой стороны, если (как указано в комментариях) вы хотите, чтобы процесс выполнялся в фоновом режиме до завершения, в то время как ваш скрипт Python продолжает выполнять другие задачи и отключать тайм-аут, вам нужно Popen.

with open("%sCOSMOSIS_output_%s.txt" % (ERROR_PATH, ini), "ab") as file,
        open("%sCOSMOSIS_output_ERROR_%s.txt" % (ERROR_PATH, ini), "a") as file_e:
    job3 = subprocess.Popen(
        ["cosmosis", ini, arg2, COSMOSIS_PATH, os.path.splitext(ini)[0] + ".txt"],
        stdout=file, stderr=file_e)
...
# time passes and your script does other things ...
job3.wait()

Возможно, вы захотите периодически poll выполнять задание, чтобы увидеть, завершено ли оно.

это полезно. Мой процесс может работать от 20 секунд до 2 часов. Я использовал тайм-аут, потому что иначе не смог бы вернуть управление с консоли, не нажимая клавишу. Любое предложение исправить это?

Ayan Mitra 28.11.2022 08:33

Исправить что? Избежать тайм-аута? Вы можете запустить фоновый процесс, если хотите, чтобы он запускал завершение, но разрешите вашему скрипту Python продолжать выполнение, и в этом случае вам нужно вернуться к Popen в конце концов (но, вероятно, все же избегать shell=True).

tripleee 28.11.2022 08:37

Да, точно. Если скрипт работает 2 часа. Он должен работать в фоновом режиме, возвращая управление автоматически, без нажатия какой-либо клавиши. Я не нашел типичного примера/предложения по этому поводу. Так что лучшее, что я мог сделать, это использовать popen. Но я предполагаю, что это не элегантно или правильно.

Ayan Mitra 28.11.2022 08:42

Это именно то, как вы это делаете. Это не очень элегантно, но это правильное решение. Я также добавил краткий фрагмент, чтобы показать это.

tripleee 28.11.2022 08:44

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