【问题标题】:Run a python script inside a running program在正在运行的程序中运行 python 脚本
【发布时间】:2017-04-22 23:35:12
【问题描述】:

我正在运行一个 python 脚本,它启动一个名为 ./abc 的可执行文件。这个可执行文件进入程序内部并等待如下命令:

$./abc
abc >                      \\waits for a command here.

我想做的是输入几个命令,例如:

$./abc
abc > read_blif alu.blif
abc > resyn2

我目前的情况如下:

import os
from array import *

os.system('./abc')
for file in os.listdir("ccts/"):
    print 'read_blif ' + file + '\n'
    print 'resyn2\n'
    print 'print_stats\n'
    print 'if -K 6\n'
    print 'print_stats\n'
    print 'write_blif ' + file.split('.')[0] + 'mapped.blif\n'

但是,这将执行以下操作:

abc >                 \\stays idle and waits until I ^C and then it prints
read ...blif
resyn2
...

它只打印到终端。我如何让它在程序中执行这个并等到它看到下一个 abc > 运行下一个命令。 谢谢

【问题讨论】:

  • 你能说清楚你想要什么吗?
  • 你正在遮蔽内置 file(对于 Python 3.4(可能完全是 Python3)没关系,但我发现这里不是这种情况)。考虑重命名它。当您从 cmdline 执行 abc 可执行文件时,它实际上做了什么?你必须更具体。
  • 很抱歉描述模糊,但下面的所有答案都是正确的。我只是想捕获程序的终端输出并向其写入命令。

标签: python bash shell sh executable


【解决方案1】:

我使用subprocess 做了类似的事情。

import subprocess

cmd = './command_to_execute'
pro = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
result = pro.stdout.read()

这将执行cmd指定的命令,然后将结果读入result。在结果分配之后执行任何操作之前,它将等待将结果打印到控制台。我相信这可能是您想要的,尽管您的描述有点模糊。

【讨论】:

    【解决方案2】:

    如果您想通过管道将命令输入可执行文件,最简单的方法是使用subprocess 模块。您可以输入可执行文件的标准输入并使用Popen.communicate 获取其输出。

    import subprocess
    
    for f in os.listdir('ccts/'):
        p = subprocess.Popen('./abc', stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = p.communicate('read_blif ' + f + '\n'
                                       'resyn2\n'
                                       'print_stats\n'
                                       'if -K 6\n'
                                       'print_stats\n'
                                       'write_blif ' + f.split('.')[0] + 'mapped.blif\n')
        # stdout will be what the program outputs and stderr will be any errors it outputs.
    

    然而,这将每次关闭子进程的stdin,但这是可靠通信而不会死锁的唯一方法。根据https://stackoverflow.com/a/28616322/5754656,您应该将pexpect 用于“类交互式会话”程序。假设您可以让不同的子进程运行程序,则可以通过拥有多个子进程来避免这种情况。

    我假设您只需要print_statsstdouts,所以您可以这样做(例如,您可能想要处理错误):

    import subprocess
    
    def helper_open(cmd='./abc'):
        return subprocess.Popen(cmd, stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    
    for f in in os.listdir('cts/'):
        helper_open().communicate('read_blif' + f + '\n'
                                  'resyn2\n')
        stats, _ = helper_open().communicate('print_stats\n')
        # Do stuff with stats
        stats, _ = helper_open().communicate('if -K 6\nprint_stats\n')
        # Do more stuff with other stats
        helper_open().communicate('write_blif ' + f.split('.')[0] + 'mapped.blif\n')
    

    【讨论】:

    • 感谢您的回答。我正在实施您为第一部分编写的内容。但是,当我尝试您的第二个建议时,我得到了ValueError: Cannot send input after starting communication。我基本上只是实现了你在第一个建议中的内容,并在每个 for 循环迭代的开始执行 subprocess.Popen,然后获取终端输出并解析它以获取统计信息。
    • @Pika 抱歉,我没有意识到 Popen.communicate 是一次性的。如果您可以多次运行可执行文件,我当前的编辑将起作用。如果不是,请在 Unix 上使用 pexpect 答案。
    • 没关系。非常感谢!我只是在将终端输出写入文件后进行解析,然后多次运行可执行文件。
    【解决方案3】:

    您需要使用subprocess 库生成一个新进程,并创建两个管道,一个用于stdin,一个用于stdout。使用此管道(在 python 中表示为文件),您可以与您的进程进行通信 这是一个例子:

     import subprocess
    
    cmd = './full/path/to/your/abc/executable'
    pro = subprocess.Popen(cmd, stdout=subprocess.PIPE, 
                           stdin=subprocess.PIPE)
    
    pro.stdin.write("read_blif alu.blif \n")
    pro.stdout.read(3)
    

    您可以使用pro.communicate,但我假设您需要为输入的每个命令获取输出。类似:

    abc > command1
    ouput1
    abc > command2
    output2 -part1
    output2 -part2
    output2 -part3
    

    这样我觉得PIPE的方法更有用。

    使用 python 中的dir 函数查找有关pro 对象的更多信息以及dir(proc) 可用的方法和属性。不要忘记内置的help 将显示文档字符串help(pro)help(pro.stdin)

    您在运行os.system 时犯了一个错误,这将在后台运行您的程序,您将无法控制它。也许你想看看什么输入/输出流。 更多阅读可以here.

    【讨论】:

      【解决方案4】:

      您可能正在寻找 pexpect 模块。这是 pexpect 文档中的基本示例

      # This connects to the openbsd ftp site and
      # downloads the recursive directory listing.
      import pexpect
      child = pexpect.spawn('ftp ftp.openbsd.org')
      child.expect('Name .*: ')
      child.sendline('anonymous')
      child.expect('Password:')
      child.sendline('noah@example.com')
      child.expect('ftp> ')
      child.sendline('lcd /tmp')
      

      如果您的操作系统与 pexpect 兼容,我认为它与 abc > 的工作方式相同。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-06-13
        • 2017-05-03
        • 2012-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多