我正在尝试编写一个启动子进程的Python脚本,并写入子进程stdin。我还希望能够确定子进程崩溃时要采取的操作。
我正在尝试启动的过程是一个名为nuke
的程序,它有自己的内置版本的Python,我希望能够提交命令,然后告诉它退出之后命令执行。到目前为止,我已经知道如果我在命令提示符上启动Python,然后启动nuke
作为子进程,那么我可以输入命令nuke
,但我希望能够把这一切都放在一个脚本中,这样主Python程序就可以启动nuke
然后写入它的standard input(从而写入它内置的Python版本)并告诉它做一些时髦的东西,所以我写了一个像这样开始nuke
的脚本:
subprocess.call(["C:/Program Files/Nuke6.3v5/Nuke6.3", "-t", "E:/NukeTest/test.nk"])
然后没有任何事情发生,因为nuke
正在等待用户输入。我现在如何写入标准输入?
我这样做是因为我正在运行一个带有nuke
的插件,导致它在渲染多个帧时间歇性地崩溃。所以我希望这个脚本能够启动nuke
,告诉它做某事然后如果它崩溃了,再试一次。
,如果有办法赶上崩溃并且仍然可以,那就太棒了。
答案 0 :(得分:70)
最好使用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]
“更好”,因为这个警告:
使用communic()而不是.stdin.write,.stdout.read或.stderr.read来避免由于任何其他OS管道缓冲区填满并阻止子进程而导致的死锁。
答案 1 :(得分:0)
您可以为stdin
的{{1}}参数提供类文件对象。
subprocess.call()
对象的documentation适用于此处。
要捕获输出,您应该使用Popen
,它使用类似的参数。来自文档:
subprocess.check_output()
答案 2 :(得分:0)
looks like在Windows 10
上用于商业版NUKE 11.3v4的方式如下:
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)
这是它在macOS 10.14
上的非商业版NUKE 11.3v4上的工作方式:
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
标志(用于图像)在GUI中运行子流程:
subprocess.Popen(['C:/Program Files/Nuke11.3v4/Nuke11.3.exe', '-v', 'E:/NukeTestImages/image.exr'], stdin=PIPE, stdout=PIPE)
希望这会有所帮助。
答案 3 :(得分:0)
要澄清一些要点:
由于jro具有mentioned,正确的方法是使用subprocess.communicate
。
但是,当使用stdin
和subprocess.communicate
向input
馈送stdin=subprocess.PIPE
时,您需要根据docs用input
来启动子流程。
请注意,如果要将数据发送到流程的stdin,则需要使用stdin = PIPE创建Popen对象。同样,要在结果元组中获取除None以外的任何内容,您还需要提供stdout = PIPE和/或stderr = PIPE。
另外qed在注释中提到,对于Python 3.4,您需要对字符串进行编码,这意味着您需要将Bytes传递给string
而不是import subprocess
command = ['myapp', '--arg1', 'value_for_arg1']
p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = p.communicate(input='some data'.encode())[0]
。这并非完全正确。根据文档,如果流以文本模式打开,则输入应为字符串(源是同一页面)。
如果以文本模式打开流,则输入必须为字符串。否则,必须为字节。
因此,如果未在文本模式下显式打开流,则应执行以下操作:
stderr
我将上面的STDOUT
值故意保留为echo -n 'CATCH\nme' | grep -i catch | wc -m
作为示例。
话虽如此,有时您可能想要另一个进程的输出,而不是从头开始构建。假设您要运行CATCH\nme
的等效项。通常,这应该返回“ CATCH”中的数字字符以及换行符,结果为6。此处的回显点是将wc
数据馈送到grep。因此,我们可以使用Python子进程链中的stdin作为变量将数据馈送到grep,然后将stdout作为PIPE传递给import subprocess
what_to_catch = 'catch'
what_to_feed = 'CATCH\nme'
# We create the first subprocess, note that we need stdin=PIPE and stdout=PIPE
p1 = subprocess.Popen(['grep', '-i', what_to_catch], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
# We immediately run the first subprocess and get the result
# Note that we encode the data, otherwise we'd get a TypeError
p1_out = p1.communicate(input=what_to_feed.encode())[0]
# Well the result includes an '\n' at the end,
# if we want to get rid of it in a VERY hacky way
p1_out = p1_out.decode().strip().encode()
# We create the second subprocess, note that we need stdin=PIPE
p2 = subprocess.Popen(['wc', '-m'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
# We run the second subprocess feeding it with the first subprocess' output.
# We decode the output to convert to a string
# We still have a '\n', so we strip that out
output = p2.communicate(input=p1_out)[0].decode().strip()
进程的stdin(同时,摆脱多余的换行符) :
12-08 16:27:12.665 2665 2695 I Unity : GPGClient:Start()
12-08 16:27:12.665 2665 2695 I Unity :
12-08 16:27:12.665 2665 2695 I Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:12.665 2665 2695 I Unity :
12-08 16:27:18.980 2665 2695 I Unity : authcode
12-08 16:27:18.980 2665 2695 I Unity : GPGClient:SignIn()
12-08 16:27:18.980 2665 2695 I Unity :
12-08 16:27:18.980 2665 2695 I Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:18.980 2665 2695 I Unity :
12-08 16:27:18.990 2665 2695 I Unity : punto0
12-08 16:27:18.990 2665 2695 I Unity : GPGClient:SignIn()
12-08 16:27:18.990 2665 2695 I Unity :
12-08 16:27:19.003 2665 2695 I Unity : Starting Auth with token client.
12-08 16:27:19.003 2665 2695 I Unity : GooglePlayGames.Android.AndroidClient:Authenticate(Action`2, Boolean)
12-08 16:27:19.003 2665 2695 I Unity : GPGClient:SignIn()
12-08 16:27:19.003 2665 2695 I Unity :
12-08 16:27:19.010 2665 2695 I Unity : punto1
12-08 16:27:19.343 2665 2695 W Unity : !!! [Play Games Plugin DLL] 12/08/19 16:27:19 +01:00 WARNING: Creating new PlayGamesPlatform
12-08 16:27:19.343 2665 2695 W Unity : System.Action:Invoke()
12-08 16:27:19.343 2665 2695 W Unity : GooglePlayGames.OurUtils.PlayGamesHelperObject:Update()
12-08 16:27:19.343 2665 2695 W Unity :
12-08 16:27:19.343 2665 2695 W Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:19.343 2665 2695 W Unity :
12-08 16:27:19.345 2665 2695 I Unity : [Play Games Plugin DLL] 12/08/19 16:27:19 +01:00 DEBUG: Activating PlayGamesPlatform.
12-08 16:27:19.345 2665 2695 I Unity : System.Action:Invoke()
12-08 16:27:19.345 2665 2695 I Unity : GooglePlayGames.OurUtils.PlayGamesHelperObject:Update()
12-08 16:27:19.345 2665 2695 I Unity :
12-08 16:27:19.345 2665 2695 I Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:19.345 2665 2695 I Unity :
12-08 16:27:19.347 2665 2695 I Unity : [Play Games Plugin DLL] 12/08/19 16:27:19 +01:00 DEBUG: PlayGamesPlatform activated: GooglePlayGames.PlayGamesPlatform
12-08 16:27:19.347 2665 2695 I Unity : System.Action:Invoke()
12-08 16:27:19.347 2665 2695 I Unity : GooglePlayGames.OurUtils.PlayGamesHelperObject:Update()
12-08 16:27:19.347 2665 2695 I Unity :
12-08 16:27:19.347 2665 2695 I Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:19.347 2665 2695 I Unity :
12-08 16:27:19.349 2665 2695 I Unity : [Play Games Plugin DLL] 12/08/19 16:27:19 +01:00 DEBUG: Creating platform-specific Play Games client.
12-08 16:27:19.349 2665 2695 I Unity : System.Action:Invoke()
12-08 16:27:19.349 2665 2695 I Unity : GooglePlayGames.OurUtils.PlayGamesHelperObject:Update()
12-08 16:27:19.349 2665 2695 I Unity :
12-08 16:27:19.349 2665 2695 I Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:19.349 2665 2695 I Unity :
12-08 16:27:19.351 2665 2695 I Unity : [Play Games Plugin DLL] 12/08/19 16:27:19 +01:00 DEBUG: Creating Android IPlayGamesClient Client
12-08 16:27:19.351 2665 2695 I Unity : System.Action:Invoke()
12-08 16:27:19.351 2665 2695 I Unity : GooglePlayGames.OurUtils.PlayGamesHelperObject:Update()
12-08 16:27:19.351 2665 2695 I Unity :
12-08 16:27:19.351 2665 2695 I Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:19.351 2665 2695 I Unity :
12-08 16:27:35.648 2665 2695 I Unity : authentication message Authentication canceled
12-08 16:27:35.648 2665 2695 I Unity : GPGClient:<SignIn>b__4_0(Boolean, String)
12-08 16:27:35.648 2665 2695 I Unity : System.Action`2:Invoke(T1, T2)
12-08 16:27:35.648 2665 2695 I Unity : System.Action:Invoke()
12-08 16:27:35.648 2665 2695 I Unity : GooglePlayGames.OurUtils.PlayGamesHelperObject:Update()
12-08 16:27:35.648 2665 2695 I Unity :
12-08 16:27:35.648 2665 2695 I Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:35.648 2665 2695 I Unity :
12-08 16:27:35.652 2665 2695 I Unity : not yet autenticated
12-08 16:27:35.652 2665 2695 I Unity : System.Action`2:Invoke(T1, T2)
12-08 16:27:35.652 2665 2695 I Unity : System.Action:Invoke()
12-08 16:27:35.652 2665 2695 I Unity : GooglePlayGames.OurUtils.PlayGamesHelperObject:Update()
12-08 16:27:35.652 2665 2695 I Unity :
12-08 16:27:35.652 2665 2695 I Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:35.652 2665 2695 I Unity :
12-08 16:27:35.654 2665 2695 I Unity : [Play Games Plugin DLL] 12/08/19 16:27:35 +01:00 DEBUG: Authentication canceled
12-08 16:27:35.654 2665 2695 I Unity : System.Action:Invoke()
12-08 16:27:35.654 2665 2695 I Unity : GooglePlayGames.OurUtils.PlayGamesHelperObject:Update()
12-08 16:27:35.654 2665 2695 I Unity :
12-08 16:27:35.654 2665 2695 I Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:35.654 2665 2695 I Unity :
12-08 16:27:35.672 2665 2695 I Unity : [Play Games Plugin DLL] 12/08/19 16:27:35 +01:00 DEBUG: Invoking user callback on game thread
12-08 16:27:35.672 2665 2695 I Unity : System.Action:Invoke()
12-08 16:27:35.672 2665 2695 I Unity : GooglePlayGames.OurUtils.PlayGamesHelperObject:Update()
12-08 16:27:35.672 2665 2695 I Unity :
12-08 16:27:35.672 2665 2695 I Unity : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
12-08 16:27:35.672 2665 2695 I Unity :
这与响应here有所不同,在响应https://firebase.google.com/docs/auth/unity/play-games中,您直接通过管道传输两个进程,而无需直接在Python中添加数据。
希望可以帮助某人。