Python子进程Popen将一个字符串传递给一个程序

JBW*_*ore 2 python subprocess

我正在尝试编写一个python脚本,将一个字符串发送到程序并将其放在后台.在命令行中,我可以复制并粘贴以下代码,并让它成功执行我想要的python程序:

printf "f\nil\ncs\n1.e-8 100.0 1.e-8\nn\n0.002\nb\n0.05\nz\n2.e-7\nx4\n5.e-7\n\n\nfort.13\nn\nn\n\n" | vpfit95
Run Code Online (Sandbox Code Playgroud)

其中:vpfit95是PATH中可执行程序的别名.

我尝试过的一些排列(一次尝试一次):

import subprocess
vpfitExecutable = 'vpfit95'

String1=r'f\nil\ncs\n1.e-8 100.0 1.e-8\nn\n0.002\nb\n0.05\nz\n2.e-7\nx4\n5.e-7\n\n\nfort.13\nn\nn\n\n'
String2=r"f\nil\ncs\n1.e-8 100.0 1.e-8\nn\n0.002\nb\n0.05\nz\n2.e-7\nx4\n5.e-7\n\n\nfort.13\nn\nn\n\n"
String3="f\nil\ncs\n1.e-8 100.0 1.e-8\nn\n0.002\nb\n0.05\nz\n2.e-7\nx4\n5.e-7\n\n\nfort.13\nn\nn\n\n"

cmd1 = "printf \"" + String1 + "\"" 
cmd2 = "printf \"" + String1 + "\" | " + vpfitExecutable 
cmd3 = "printf \"" + String2 + "\"" 
cmd4 = "printf \"" + String3 + "\"" 

print cmd2

p1 = subprocess.Popen([vpfitExecutable, cmd1])
p2 = subprocess.Popen([cmd2])
p3 = subprocess.Popen([vpfitExecutable, cmd3])
p4 = subprocess.Popen([vpfitExecutable, cmd4])
p4 = subprocess.Popen([vpfitExecutable, String1])
p5 = subprocess.Popen([vpfitExecutable, String2])
p6 = subprocess.Popen([vpfitExecutable, String3])

# check
p7 = subprocess.Popen([vpfitExecutable]) # works.
Run Code Online (Sandbox Code Playgroud)

一切都失败了(除了p7).有些失败了"Fortran运行时错误:文件结束"(来自vpfit程序).其他人失败了一个Traceback到子进程库和"OSError:[Errno 2]没有这样的文件或目录".

一些检查:当我打印cmd2并复制并粘贴到终端时,它完美地工作.当我运行时p7,它正确地开始按预期运行程序,只是没有输入字符串.我显然在这里缺少一些基本的东西,而我却无法弄清楚是什么.任何帮助赞赏!

wim*_*wim 6

是的,你缺少一些基本的东西 - 管道由shell处理.要使用子进程执行所需操作,应将其vpfit95作为子进程运行,然后再运行communicate它.请参阅文档的第17.1.4.2节,替换shell管道.

proc = subprocess.Popen([vpfitExecutable], stdin=subprocess.PIPE)
proc.communicate(input='your string') 
Run Code Online (Sandbox Code Playgroud)

如果你需要检查vpfit的stdout和stderr,那么从输出元组中获取句柄communicate.

一个脏的替代方法是运行命令shell=True,在shell中生成它然后你可以在命令中使用管道,但是"切断中间人"并直接与子进程交互更清晰.