【问题标题】:How to use running output from the console in another program如何在另一个程序中使用控制台的运行输出
【发布时间】:2019-01-10 01:22:25
【问题描述】:

我正在从命令行运行一个程序。这个程序打印出我的一些 CPU 的统计数据(如果有人感兴趣,可以链接到程序:https://github.com/opcm/pcm)。程序不退出。它会在同一个终端定期打印更新的统计信息。

我正在尝试在我自己编写的另一个程序中使用程序正在检索的这些统计信息。我正在编写的程序只是应该在 python 中实时绘制这些 CPU 统计数据与时间的关系图。

我不确定如何在我的程序中实时检索和使用打印到控制台的统计信息。我知道我可以通过键入./program.x > output.txt 将输出直接输出到文本文件而不是控制台。

我的第一个想法是将输出的统计信息推送到文本文件,同时在我的程序中从该文本文件中读取。但这感觉像是一种蛮力方法,我不确定它是否会起作用。

有谁知道我如何在另一个程序中使用一个程序的实时输出?

【问题讨论】:

  • 这听起来像是管道的工作。您是否为您的用例考虑过管道?
  • @CharlesLandau 我从未听说过或使用过管道。我会查一下它们是什么/它们是如何使用的。
  • 我会用管道发布答案
  • 间接复制:stackoverflow.com/questions/375427/…,因为输出应该从子进程中读取。
  • @Kingsley 我寻找了类似的问题,但找不到任何东西。也许我的问题的措辞是问题所在,以及为什么我没有得到相关的帖子(或者只是我缺乏管道知识)。我很抱歉。

标签: python terminal


【解决方案1】:

您可以通过多种方式实现此结果。

在 unix 系统上,我认为最简单的方法是使用管道 假设您有 program1 (p1) 输出一些数据和 program2(p2) 读取和使用这些数据。

您可以按照@Charles Landau 的建议使用| 将p1 的输出通过管道传输到p2,这会在两个程序的stdout 和stdin 之间创建一个管道

./p1 | p2

如果您还想可视化 p1 的输出,您可以使用 tee,它获取标准输入并将其分叉到标准输出和程序

./p1 | tee p2

现在这只有在您打算同时启动 p1 和 p2 时才有效(此时相信最好将其设为单个程序)。 管道的更通用用法是让 p1 创建一个命名管道 (FIFO) 并让 p2 从这个管道中读取:

p1.py(服务器)

import os
from random import randint
import time

FIFO="/tmp/test_fifo"

if not os.path.exists(FIFO):
    os.mkfifo(FIFO)

pipe = os.open( FIFO, os.O_RDWR) #I use this to avoid the program hanging on this step.
                                 #When you open a FIFO, the behavior is blocking, meaning that the program will hang until both end (r/w) of the pipe are being used
f = os.fdopen( pipe, "w")        #Then i want a file object so i can flush it

while 1:
    # Do operation
    output = randint(0,999999)
    # Print output
    print(output)

    # Send output into pipe
    f.flush()
    f.write( str(output) + '\n')
    time.sleep(0.5)

f.close()
pipe.close()

os.unlink(FIFO)

p2.py(客户端)

import os
import sys

FIFO="/tmp/test_fifo"

if not os.path.exists(FIFO):
    exit()

f = open( FIFO, "r")

while 1:
    read_fifo = f.readline()
    print( read_fifo, end='')
    sys.stdout.flush()

您也可以使用 shell 对 linux 中的 FIFO 进行一些简单的测试

mkfifo 1
shell1: tail -f 1
shell2: echo "Hello!" > 1

以类似的方式,您可以使用 TCP 协议让 2 程序进行通信 有关此方法的更多信息,请参阅 python https://docs.python.org/3/library/socket.html

【讨论】:

  • 请参阅我正在使用 PCM 工具获取 CPU 功率统计数据作为 p1,我自己的作为 p2。我真的无法编写一个程序来执行此操作,因为我认为我不应该编辑 PCM 的源代码。
  • @Mr.Mips 我看到您使用的代码还提供了一个 API,这意味着应该可以将其作为模块导入并使用其函数调用为其编写自己的包装器输出。
  • @Mr.Mips 您可以尝试的另一种可能性是使用类似 mkfifo name_of_fifo; ./pcm | tee name_of_fifo,然后使用第二个程序从这个 fifo 中读取。唯一的问题是只有在 FIFO 缓冲区已满时才会刷新输出。另一个问题是,根据程序行为,命令可能会挂起,直到您也开始从 FIFO 读取。 (例如 mkfifo 1; python > 1 和在 shell2 中:tail -f 1 不会阻塞,但只有在 FIFO 被填充类似 while 1: print("HI") 的东西后才会开始打印输出)
【解决方案2】:

你可以在 python 中制作类似 tail 的东西。这是代码示例,但如果文件被删除,则无法处理。

def tail_F(some_file):
    while True:
        try:
            for line in sh.tail("-f", some_file, _iter=True):
                yield line
                # do whatever with new line
        except sh.ErrorReturnCode_1:
            yield None

【讨论】:

    【解决方案3】:

    听起来你想要管道。管道获取程序的标准输出并将其直接传递给下一个程序。我能想到的最简单的例子:

    ls | grep ".bin"
    

    很容易记住,因为管道运算符有点像管道|

    关于管道的更多信息:http://web.cse.ohio-state.edu/~mamrak.1/CIS762/pipes_lab_notes.html

    编辑:使用sys.stdin 永久读取管道已得到很好的解释here

    从中汲取的重要模式就在那里:

    import sys
    while True:
        line = sys.stdin.readline()
        # do something with line
    

    【讨论】:

    • 如何从管道中获取程序中的输入,该管道在 python 中获取其他程序的输出?
    • @Mr.Mips 简短的答案是sys.stdin,我将在上面编辑我的答案
    • 所以我做了两个程序用于测试。一个将数字打印到控制台(称为 Runner),另一个的代码正是您给我的代码,除了我在 while 循环中添加了 print(line) 部分(称为 Capture)。当我运行Runner | Capture(其中 Runner 和 Capture 是我的代码编译的文件)时,它不起作用并显示“未找到 Runner 和 Capture 命令”。我如何将管道与我自己编译的程序一起使用?
    • 这将是一个单独的问题,您可以在 SO 上发布,但听起来您的程序不在 PATH 中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-12
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2012-12-12
    • 1970-01-01
    相关资源
    最近更新 更多