Как передать содержимое переменной через два цепных канала в Python?

1

Мне удалось успешно передать переменную команде, которая далее не транслируется:

from subprocess import Popen, PIPE

def exec_command(command, some_input):
    proc = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
    (stdout, stderr) = proc.communicate(input=some_input)

... но при попытке подключить его к другой команде с каналами (например, для конвейера tar, а затем для дальнейшего разделения каналов), он не работает:

from subprocess import Popen, PIPE

def exec_piped_command(command1, command2, some_input):
    proc1 = Popen(command1, stdout=PIPE, stdin=PIPE)
    proc2 = Popen(command1, stdin=proc1.stdout, stdout=PIPE)
    (stdout, stderr) = proc2.communicate(input=some_input)[0]

Итак, как правильный способ сделать этот второй вариант? Похоже, проблема с указанным выше кодом заключается в том, что вход в команду proc2.communicate() не доходит до stdin-канала proc1? (Не уверен, хотя... к несчастью, я немного смущен синтаксисом подпроцесса...).

  • 0
    proc2.communicate пытается передать некоторые входные данные в PIPE, но входная PIPE для proc2 снабжена выходной PIPE из proc1 --- Каналы Unix не поддаются нескольким процессам записи / чтения (они НЕ похожи на объекты Queue; ни как розетки). Это, вероятно, приводит к тупику в вашем коде.
  • 0
    Да, правда, поэтому мой вопрос в том, как передать переменную на вход proc1 и по-прежнему выполнять всю цепочечную команду? ... выполнение proc1.communicate (input = some_input) также не работает ...
Показать ещё 5 комментариев
Теги:
subprocess
pipe

1 ответ

1
Лучший ответ

Одна из возможностей состоит в том, чтобы настроить всю команду, которая будет выполнена оболочкой (shell=True, среди ключевых слов вашего вызова Popen()... и только .communicate() с концами всего конвейера ( ваш вход идет в команду1 stdin, а ваш stdout/stderr поступает из command2 stdout/stderr).

Более сложный, но мелкозернистый подход будет заключаться в использовании os.fork() наряду с os.pipe() и os.dup2() и, возможно, с некоторыми os.fcntl() вызовами для настройки ваших собственных подпроцессов, с вашим собственным пользовательским переполнением и любые требуемые характеристики блокировки/неблокирования, которые вам нужны в ваших файловых дескрипторах, а затем, наконец, используя ваши собственные функции os.exec* в каждом из них.

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

Средней дорогой было бы сделать подкласс, который наследует от subprocess.Popen

Конечно, может быть предпочтительнее выполнять некоторые части этого конвейера через код и модули Python (такие как операции tar, gzip и split).

  • 0
    Спасибо, я пошел за простое решение с Shell = True. К сожалению, немного менее безопасным, но я надеюсь, что все будет в порядке, если в команду не добавлять контролируемые пользователем строки ...

Ещё вопросы

Сообщество Overcoder
Наверх
Меню