Получение вывода PV с подпроцессом
Я пишу скрипт для автоматизации импорта базы данных в MySQL. Я пытаюсь написать код, который отображает вывод pv
как база данных импортируется:
pv = subprocess.Popen(
["pv", "-f", restore_filepath],
bufsize=1,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
universal_newlines=True,
shell=True,
)
subprocess.Popen(
[
"mysql",
"-u{}".format(db_user),
"-p{}".format(db_pass),
db_name,
],
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
stdin=pv.stdout,
)
for line in pv.stderr:
print("hello")
sys.stdout.write("\r" + line.rstrip("\n"))
sys.stdout.flush()
Это основано на коде в этом вопросе, но это не работает для меня. hello
даже не печатается, даже если я закомментирую другие строки в цикле for - for line in pv.stderr
блокирует, и я не знаю почему. Он никогда не разблокируется, поэтому, даже когда процесс завершен, программа все еще застряла - я должен убить ее.
Что я делаю не так, что вызывает for line in pv.stderr
блокировать?
1 ответ
Когда shell = True, args[0]
команда должна быть выполнена и args[1:]
аргументы переданы sh
, Ты хочешь -p
а также restore_filepath
быть переданным pv
не sh
, Так что используйте shell=False
, То же самое относится и к другим subprocess.Popen
вызов.
Так как с shell=True
,pv
не получает никаких аргументов, поэтому он зависает, потому что все еще ждал имя файла. Итак, еще раз, решение заключается в использовании shell=False
,
Также обратите внимание, что при замене конвейера оболочки вы должны закрыть stdout
на первом процессе, чтобы позволить ему получить SIGPIPE, если существует второй процесс. Это позволяет некоторым программам (тем, которые обрабатывают SIGPIPE) более корректно завершать работу, если конвейер не работает.
pv = subprocess.Popen(
["pv", "-f", restore_filepath],
shell=False, # optional, since this is the default
bufsize=1,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
universal_newlines=True,
)
mysql = subprocess.Popen(
["mysql",
"-u{}".format(db_user),
"-p{}".format(db_pass),
db_name],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
stdin=pv.stdout,
)
pv.stdout.close() # Allow pv to receive a SIGPIPE if mysql exits.
for line in pv.stderr:
print("hello")
sys.stdout.write("\r" + line.rstrip("\n"))
sys.stdout.flush()