У меня есть следующий фрагмент кода в виде скрипта Python. Я получаю правильные выходные файлы задания без ошибок. Однако файлы журнала stdout
subprocess
(например, 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()
Прежде всего, вы просто открываете файл, вы ничего из него не читаете, вы нигде не храните информацию о файле, поэтому он просто создаст этот <_io.TextIOWrapper name=9 encoding='UTF-8'>
, который очень легко воспроизвести:
file = open("testtextf.txt","a")
print(file)
Вы должны прочитать это как-то, например, с помощью .read()
:
data = file.read()
Также я не рекомендую использовать «открыть», если вы не хотите иметь дело с файлами, оставленными открытыми, если что-то пойдет не так между строками, прежде чем вы снова закроете его.
Я настоятельно рекомендую вместо этого использовать «с открытым».
Хорошо, следующий фрагмент является достаточным решением вопроса, опубликованного выше.
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, но не на других платформах (ну, вы можете заставить это работать, но вы должны знать, что делаете). Вероятно, избегайте этого сочетания.
Я не работаю с окнами. Это очень хорошо работает в Linux.
Квадратные скобки вокруг строки не нужны и несколько вводят в заблуждение. Вы должны передать только строку с shell=True
или правильно разделенный список токенов без (попробуйте shlex.split()
или просто не склеивайте части вместе). Смотрите также Фактическое значение shell=True в подпроцессе
@AyanMitra Если вы не хотите, чтобы этот ответ оставался здесь, вы можете удалить его самостоятельно, используя ссылку «Удалить» выше.
Передача списка в качестве первого аргумента с 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 часов. Я использовал тайм-аут, потому что иначе не смог бы вернуть управление с консоли, не нажимая клавишу. Любое предложение исправить это?
Исправить что? Избежать тайм-аута? Вы можете запустить фоновый процесс, если хотите, чтобы он запускал завершение, но разрешите вашему скрипту Python продолжать выполнение, и в этом случае вам нужно вернуться к Popen
в конце концов (но, вероятно, все же избегать shell=True
).
Да, точно. Если скрипт работает 2 часа. Он должен работать в фоновом режиме, возвращая управление автоматически, без нажатия какой-либо клавиши. Я не нашел типичного примера/предложения по этому поводу. Так что лучшее, что я мог сделать, это использовать popen
. Но я предполагаю, что это не элегантно или правильно.
Это именно то, как вы это делаете. Это не очень элегантно, но это правильное решение. Я также добавил краткий фрагмент, чтобы показать это.
Спасибо. Не могли бы вы предоставить полный воспроизводимый фрагмент?