0

我正在尝试捕获和/或删除由 os.system() 调用启动的命令的输出。该脚本将在 Linux 和 Windows 下运行。

我不能使用 subprocess 模块,因为所述命令是交互式的(即:用户可以键入指令来触发各种操作)。因此,请不要将此线程作为常见问题的副本提及,例如:

  1. Python:运行 os.system 后如何获取标准输出?
  2. 如何在 python 中存储它打印到 stdout 的 os.system 的返回值?
  3. 将 os.system 的输出分配给一个变量并阻止它显示在屏幕上
  4. ...

一种解决方案可能是让子进程与这样一个“包装”的程序一起工作,但这似乎是一项相当复杂的任务,我想保持解决方案简单(没有外部模块或 1000 行代码片段......),因为它不是我的脚本的主要功能。以下线程似乎很有希望,但它们的工作不如粗略的 os.system() (也不是那么简单......):

  1. 从 python 中运行交互式命令
  2. 在 python 中对 subprocess.PIPE 进行非阻塞读取
  3. http://log.ooz.ie/2013/02/interactive-subprocess-communication-in.html

另一种解决方案可能是制定一个“tee”功能,例如 Linux 发行版中本机支持的功能。例如,我在这里找到了一个很好的实现(一个修改 sys.stdout 以写入文件和原始 sys.stdout 的 Tee 类):

问题是 os.system() 似乎没有打印到主脚本标准输出。相反,它在子shell中启动程序,我找不到检索/抑制其输出的方法......

如果您有任何其他方法或解决方案,请告诉我们。谢谢。


在下面的评论中询问并给出了有关上下文的一些细节。当子进程似乎是明显的解决方案时,主要的询问与为什么我坚持使用 os.system() 有关。

我执行的程序称为 CAST3M ( http://www-cast3m.cea.fr/ )。它是一种有限元代码,用于解决物理各个领域的问题。没有 GUI,因此用户通过称为 GIBIANE 的命令行自定义语言进行交互。传统上,您可以为 CAST3M 提供预先编写的 GIBIANE 数据文件,或者在没有数据文件的情况下启动程序并即时输入命令。以下是典型的 GIBIANE 指令(它们定义了一些点,然后是一条线、一个正方形,最后是一个立方体):

OPTI 'DONN' 3 'ELEM' 'CUB8' ;
PT1 = 0. 0. 0. ;
PT2 = 1. 0. 0. ;
PT3 = 0. 1. 0. ;
PT4 = 0. 0. 1. ;
NN1 = 5 ;
DR1 = PT1 DROI NN1 PT2 ;
SF1 = DR1 TRAN NN1 PT3 ;
VL1 = SF1 VOLU 'TRAN' NN1 PT4 ;

我用 Python 制作了一个包装器,旨在在实际启动 CAST3M 之前调整它的一些功能。我需要记录这个 Python 脚本打印的内容以及 CAST3M 会话的输出。当没有交互性时,子流程会完成这项工作。当有交互性时,我被迫使用 os.system() 因为子进程与 CAST3M 的工作很差(我只需要将它交给 CAST3M,os.system() 开箱即用,但代价是IO 控制是真的)

4

2 回答 2

1

=> 正如 Martijn Pieters 所说,没有办法检索 os.system() 调用的标准输出(因为它产生了一个子shell = 一个黑盒子,我们只知道它的返回码)。然后解决方案是让 Python 充当最终用户和 CAST3M 之间的代理(传递配置:Python 是“中间人”,侦听用户请求并将其“按原样”传输到 CAST3M,然后捕获 CAST3M 答案和将其打印回用户)。为此,您必须使用子进程、线程和队列模块。如果您不介意它带来的复杂性(以及对原始 HCI 体验的改变),这里是链接的快速摘要,可能会发现有用的信息:

  1. 包装子进程的标准输出/标准错误
  2. 你能像往常一样制作一个python子进程输出stdout和stderr,但也可以将输出捕获为字符串吗?
  3. 从 python 中运行交互式命令
  4. 在 python 中对 subprocess.PIPE 进行非阻塞读取
  5. http://log.ooz.ie/2013/02/interactive-subprocess-communication-in.html

=> Robᵩ 通过将日志记录任务指定给“脚本”Linux 工具,仅为 Linux 提供了一种解决方法。这允许保持“user<>CAST3M”交互性不变(这里没有代理)。

于 2013-10-30T09:29:10.030 回答
0

在 Linux 上,script提供了一个交互环境,同时捕获所有用户交互:

os.system("script -c '/bin/ed /etc/passwd' /tmp/capture_file")

上面的函数调用将调用ed密码文件的行编辑器。所有的用户交互都将存储在/tmp/capture_file.

于 2013-10-29T15:44:26.393 回答