【问题标题】:Inputs not working using subprocess with Python输入在 Python 中使用子进程不起作用
【发布时间】:2021-06-01 17:37:22
【问题描述】:

我正在尝试使用 Python 运行 AVL(Athena Vortex Lattice)。它是一个在单独的终端窗口上运行的软件,与 XFOIL 完全一样。用户编写命令后按enter执行。

我正在使用subprocess 模块运行软件,终端窗口按预期打开。但是,我无法让我的 Python 程序将命令写入打开的窗口。我没有收到任何错误,但没有向 AVL 写入任何内容,并且它保持初始状态。

我尝试写入 AVL 的命令是 LOAD,后跟输入文件的绝对路径。

这是我第一次使用 subprocess 模块,所以我可能只是忘记了某个地方的基本选项。我在 macOS 上使用 Python 3.9 运行程序。

可能出了什么问题?

import os.path
import subprocess as sp

AVL_FOLDER_PATH = '~/Desktop/AVL_VLM'
AVL_EXE_NAME = 'avl335'
avl_path = os.path.join(AVL_FOLDER_PATH, AVL_EXE_NAME)
avl_open_cmd = 'open ' + avl_path

avl_ps = sp.Popen([avl_open_cmd], stdin=sp.PIPE, stdout=None, stderr=None, shell=True)

def avl_command(cmd):
    cmd += '\n'
    cmd = cmd.encode('ascii')
    avl_ps.stdin.write(cmd)

avl_command('LOAD')
avl_command('/Users/vianneydubois/Desktop/AVL_VLM/test_gen.avl')

【问题讨论】:

  • shell=True 在这里可能是错误的,但是你的命令需要是['open', avl_path]。或许还可以参见Actual meaning of shell=True in subprocess... 并可能让 Python 为您扩展路径中的波浪号。
  • 从我从 AVL 文档中可以看出,LOAD 命令和文件名应该在同一行,用空格分隔。您将它们完全放在不同的行上。
  • LOAD 命令和文件名可以在不同的行上,当我手动执行它时它可以工作,并且我已经看到使用每行命令的自动脚本,所以这不是我认为的问题所在。 ..
  • 这里为什么需要open?如果avl335 实际上是您的可执行文件的名称,那么只需运行它。 open 是一个 MacOS 的东西,它试图找到与给定数据文件关联的可执行文件。
  • 另外你的命令行中不能有空格。打开并且您的路径需要成为列表的一部分。

标签: python subprocess


【解决方案1】:

输入/输出默认缓冲 (https://docs.python.org/3/library/subprocess.html#subprocess.Popen)

你可以在Popen中设置bufsize=0

0 表示无缓冲(读写是一个系统调用,可以短返回)

(https://docs.python.org/3/library/subprocess.html#subprocess.Popen)

作为替代方案,您可以在写入后手动刷新缓冲区:

avl_ps.stdin.write(cmd)
avl_ps.stdin.flush()

【讨论】:

  • 我在编写命令后添加了.flush(),它几乎可以工作了......新的问题是,当我添加更多命令时,程序在执行过程中停止,在随机位置。我的意思是,如果我多次运行 Python 程序,AVL 执行在完成之前就停止了,它总是在不同的时间,有时它在开始时停止,有时是在计算过程中,之后一些命令已成功编写
【解决方案2】:

这真的是你想要的吗?

import os.path
import subprocess as sp

AVL_FOLDER_PATH = '~/Desktop/AVL_VLM'
AVL_EXE_NAME = 'avl335'
avl_path = os.path.join(AVL_FOLDER_PATH, AVL_EXE_NAME)


def avl_command(cmd):
    return sp.run(cmd, capture_output=True, shell=True)

ret = avl_command(['open ', avl_path])
ret = avl_command(['LOAD','/Users/vianneydubois/Desktop/AVL_VLM/test_gen.avl'])

或者你的意思是:

ret = avl_command('open' + avl_path + '; LOAD /Users/vianneydubois/Desktop/AVL_VLM/test_gen.avl')
print(ret.stdout.decode())

【讨论】:

  • 我试过你的代码,删除了 Tim Roberts 上面建议的 open 命令,但结果是一样的,AVL 在终端中运行,但是 LOAD 和以下命令不是用 AVL 编写的
  • LOAD 命令在做什么,它需要输入吗?或者这都是初始打开命令的一部分?
  • LOAD 命令要求用户写入输入文件名。您可以写LOAD myfile.avl 或单独写LOAD 然后myfile.avl。然后程序读取输入文件。
  • 所以我的第一个选择就是你想要的。您希望在同一个会话中使用这个?
猜你喜欢
  • 2013-10-15
  • 2016-03-01
  • 2018-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-08
  • 2014-10-14
  • 2018-12-06
相关资源
最近更新 更多