【问题标题】:How to unbuffer stdout of legacy running binary without stdbuf and similar tools如何在没有 stdbuf 和类似工具的情况下取消缓冲传统运行二进制文件的标准输出
【发布时间】:2018-01-09 16:31:38
【问题描述】:

我想监控我将要启动的程序的实时输出。我试图通过将程序的输出重定向到管道然后从监视脚本中读取管道来做到这一点。

./program >> apipe

然后从监控脚本

cat apipe

但是由于 >> 中的缓冲区,没有输出。无论如何我可以禁用这个缓冲区?我在准系统嵌入式系统 (petalinux) 上运行,因此我无法访问 unbuffer、脚本或 stdbuf 来帮助我。

我已经在另一个可以使用 unbuffer 的平台上尝试了这些脚本,它按我的预期工作。

有什么方法可以配置这个缓冲区,或者使用另一个二进制文件来重定向?

编辑:我无权访问我尝试运行的命令的源代码。它是旧版二进制文件。

【问题讨论】:

    标签: bash pipe buffer petalinux


    【解决方案1】:

    如果您无权访问stdbuf,您不妨模拟它并手动解除stdout 的缓冲gdb(假设您显然可以访问gdb) .

    让我们来看看stdbuf 是如何实际操作的。 stdbuf GNU coreutils 命令基本上只通过设置LD_PRELOAD 环境变量在用户程序中注入libstdbuf。 (无关紧要,但为了记录,选项是通过_STDBUF_E/_STDBUF_I/_STDBUF_O env vars 传递的。)

    然后,当 libstdbuf 运行时,它会在适当的文件描述符 (stdin/stdout/stderr) 上调用 setvbuf libc 函数(它依次执行底层系统调用),并使用适当的模式(完全缓冲、行缓冲或无缓冲)。

    setvbuf 的声明在stdio.h 中,可通过man 3 setvbuf 获得:

    #include <stdio.h>
    
    int setvbuf(FILE *stream, char *buf, int mode, size_t size);
    

    mode 的值为:_IONBF_IOLBF_IOFBF,如stdio.h 中所定义。我们在这里只对无缓冲模式感兴趣:_IONBF。它的值为2(您可以查看您的/usr/include/stdio.h)。

    解缓冲脚本

    所以,要为某个进程取消缓冲 stdout,我们只需要调用:

    setvbuf(stdout, NULL, _IONBF, 0)
    

    我们可以通过gdb 轻松做到这一点。让我们编写一个可以调用的脚本,unbuffer-stdout.sh:

    #!/bin/bash
    # usage: unbuffer-stdout.sh PID
    
    gdb --pid "$1" -ex "call setvbuf(stdout, 0, 2, 0)" --batch
    

    那么,我们可以这样称呼它:

    $ ./unbuffer-stdout.sh "$(pgrep -f my-program-name)"
    

    (您可能需要sudoroot 运行它。)

    测试

    我们可以使用这个带有缓冲标准输出的简单 Python 程序(如果没有使用 -u 调用,并且未设置 PYTHONUNBUFFERED),writer.py

    #!/usr/bin/python
    import sys, time
    
    while True:
        sys.stdout.write("output")
        time.sleep(0.5)
    

    运行它:

    $ ./writer.py >/tmp/output &
    $ tailf /tmp/output
    

    并观察在我们运行之前没有输出:

    $ sudo ./unbuffer-stdout.sh "$(pgrep -f writer.py)"
    

    【讨论】:

    • 哇,很好的答案,我目前正在探索使用 GDB 执行此操作,但我主要关心的是性能。这个二进制文件是相当关键的任务,我们不能承受性能损失。这是一个有效的担忧吗?
    • 好吧,你只需要这样做一次。在我的系统上,完整的修补需要 30 毫秒。我不知道这是否能满足您的需求。
    猜你喜欢
    • 1970-01-01
    • 2015-01-09
    • 2010-09-14
    • 2013-11-28
    • 2011-03-20
    • 1970-01-01
    • 2018-10-29
    • 2019-09-04
    • 1970-01-01
    相关资源
    最近更新 更多