Как мне написать в стандартный подпроцесс Python? - PullRequest
52 голосов
/ 12 декабря 2011

Я пытаюсь написать скрипт Python, который запускает подпроцесс и записывает в подпроцесс stdin. Я также хотел бы иметь возможность определить действие, которое необходимо предпринять в случае сбоя подпроцесса.

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

subprocess.call(["C:/Program Files/Nuke6.3v5/Nuke6.3", "-t", "E:/NukeTest/test.nk"])

Тогда ничего не происходит, потому что nuke ожидает ввода пользователя. Как бы мне теперь написать в стандартный ввод?

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

Ответы [ 3 ]

72 голосов
/ 12 декабря 2011

Может быть лучше использовать communicate:

from subprocess import Popen, PIPE, STDOUT
p = Popen(['myapp'], stdout=PIPE, stdin=PIPE, stderr=PIPE)
stdout_data = p.communicate(input='data_to_write')[0]

«Лучше», из-за этого предупреждения:

Используйте функцию connect () вместо .stdin.write, .stdout.read или .stderr.read, чтобы избежать взаимных блокировок из-за того, что любой из других буферов буфера ОС заполняет и блокирует дочерний процесс.

0 голосов
/ 27 мая 2019

Вот как это выглядит для коммерческой версии NUKE 11.3v4 на Windows 10:

import subprocess

# Run NUKE's script in Terminal mode on Windows machine...
subprocess.Popen(['C:/Program Files/Nuke11.3v4/Nuke11.3.exe', '-t', 'E:/NukeTest/test.nk'], stdin=PIPE, stdout=PIPE)

Вот как это работает для некоммерческой версии NUKE 11.3v4 на macOS 10.14:

import subprocess
from subprocess import Popen, PIPE
import time

# Run NUKE's script in Terminal mode on MacOS machine...
np = subprocess.Popen(['/Applications/Nuke11.3v4/NukeX11.3v4 Non-commercial.app/NukeX11.3v4 Non-commercial', '-t', '/Users/<username>/Desktop/test.nknc'], stdin=PIPE, stdout=PIPE)

# Choose a method to wait for the subprocess to finish...
np.wait() 
time.sleep(5)        

data = np.communicate(input='data')[0]

print(data)

Результат выглядит следующим образом:

'''
NukeX 11.3v4, 64 bit, built May  1 2019.
Copyright (c) 2019 The Foundry Visionmongers Ltd.  All Rights Reserved.
Non-commercial mode active.
Licence expires on: 2019/7/27
(11, 3, 4)
('darwin', 'posix')
/Applications/Nuke11.3v4/Nuke11.3v4.app/Contents/MacOS/../Frameworks/Python.framework/Versions/Current/
Disk cache /var/tmp/nuke-u501/ViewerCache/??: 424MB (5% of 10240MB) used in 81 files.

'''

Кроме того, вы можете запускать подпроцесс в графическом интерфейсе, используя -v флаг для изображений:

subprocess.Popen(['C:/Program Files/Nuke11.3v4/Nuke11.3.exe', '-v', 'E:/NukeTestImages/image.exr'], stdin=PIPE, stdout=PIPE)

Надеюсь, это поможет.

0 голосов
/ 12 декабря 2011

Вы можете предоставить файлоподобный объект для аргумента stdin, равного subprocess.call().

Здесь применима документация для объекта Popen.

Для захвата вывода вы должны вместо этого использовать subprocess.check_output(), который принимает аналогичные аргументы. Из документации:

>>> subprocess.check_output(
...     "ls non_existent_file; exit 0",
...     stderr=subprocess.STDOUT,
...     shell=True)
'ls: non_existent_file: No such file or directory\n'
...