Создать пустой объект Popen () в Python? - PullRequest
1 голос
/ 08 марта 2012

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

Я приведу пример кода, чтобы показать, что япытаясь выполнить:

com = [["ls","/"],["wc"]]
p = Popen(["echo"])
for c in com:
     p = Popen(c, stdin=p.stdout,stdout=PIPE,stderr=PIPE)
l = list(p.communicate())

У меня есть вложенный список, содержащий системные команды, которые я хотел бы выполнить, перебирая список, но для того, чтобы это работало, p, конечно, должен существовать в началеПервая итерация.Я могу решить эту проблему, как я сделал, просто выполнив эхо, но мне было интересно, есть ли более аккуратный и более правильный путь?

Ответы [ 3 ]

1 голос
/ 08 марта 2012

Если все, что вам нужно, это запустить конвейер (= одну или несколько | -разделенных команд), который передается вашей функции во время выполнения, нет необходимости переходить ко всем этим проблемам: просто используйте subprocess.Pipe(pipeline, shell=True). Он будет обрабатывать трубы самостоятельно. («pipe» - это одна строка, например, "ls" или "ls / | wc")

Если по какой-то причине вы действительно хотите запустить их как отдельные каналы, ваш вопрос сводится к следующему: у вас есть цикл, но вам нужно начальное значение для его запуска. Вместо того, чтобы тратить звонок на Попена, я бы сделал это так:

com = [["ls","/"],["wc"]]
p = None
for c in com:
    p = Popen(c, stdin=(p.stdout if p else None), stdout=PIPE, stderr=PIPE)

(PS. Я отказался от своего старого ответа, поскольку неправильно понял, что вы делаете).

1 голос
/ 08 марта 2012

То, что вы хотите здесь, это (по-видимому) серия труб:

com[0] | com[1] | ... | com[n-1]

Самый простой способ, если вам не нужно беспокоиться о «плохих» персонажах и оболочках, это просто объединить их всех в одну большую команду оболочки:

p = subprocess.Popen(' | '.join(' '.join(words) for words in com), shell=True, ...)

В качестве альтернативы, так как изначально вы хотите, чтобы stdout = None, вы можете использовать хитрость @ pst, заключающуюся в том, чтобы p изначально был любым объектом с .stdout, равным None. Но вы также должны заметить, что вы зависите от системы, которая закрывает каждый из ваших предыдущих подпроцессов.Popen () (так, чтобы их выходные каналы были близки () d) внутри цикла, что происходит с CPython, но не с Jython ( насколько я понимаю - я на самом деле не использовал Jython). Так что вам может понадобиться более явный цикл:

# assumes len(com) >= 1
p0 = subprocess.Popen(com[0], stdout=subprocess.PIPE)
# don't use stderr=subprocess.PIPE -- if you want stderr to be piped too
# use stderr=subprocess.STDOUT, or create a stderr pipe early manually and
# supply the fd directly; see hints in text below.
for words in com[1:]:
    p1 = subprocess.Popen(words, stdin=p0.stdout, stdout=subprocess.PIPE)
    # again you don't want to set stderr to subprocess.PIPE here
    p0.stdout.close() # now that it's going to p1, we must ditch ours
    p0 = p1 # p1 becomes the input to any new p1 we create next time
# at this point, use p0.communicate() to read output

Если вы перенаправите stderr = subprocess.STDOUT в каждом Popen (), это перенаправит вывод ошибок из каждой подкоманды в следующую. Чтобы передать их все в вашу программу, вам сначала нужно создать объект канала на уровне ОС, затем подключить каждый к концу записи этого (одного) канала, а затем пробраться вокруг модуля подпроцесса, чтобы получить «конечный» объект подпроцесса, указывающий на него. , так что его код выбора / опроса будет высасывать любые данные из этого канала. (Поскольку subprocess.communicate () будет считывать только кратные данные из двух таких каналов, вы не можете захватывать выходные данные stderr каждой отдельной подкоманды.)

Примечание: ничего из вышеперечисленного не проверено ...

1 голос
/ 08 марта 2012

В Unix может быть немного предпочтительнее использовать true, чем echo.true - это программа, которая ничего не делает и всегда добивается успеха (см. Страницу руководства для смешка).

...