Получение вывода PV с подпроцессом - PullRequest
0 голосов
/ 31 декабря 2018

Я пишу скрипт для автоматизации импорта базы данных в 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 Ответ

0 голосов
/ 31 декабря 2018

Когда 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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...