如何写入Python子进程'stdin?

时间:2011-12-12 13:46:56

标签: python subprocess stdin nuke

我正在尝试编写一个启动子进程的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,告诉它做某事然后如果它崩溃了,再试一次。

,如果有办法赶上崩溃并且仍然可以,那就太棒了。

4 个答案:

答案 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 likeWindows 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

但是,当使用stdinsubprocess.communicateinput馈送stdin=subprocess.PIPE时,您需要根据docsinput来启动子流程。

  

请注意,如果要将数据发送到流程的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中添加数据。

希望可以帮助某人。