如何在没有 stdbuf 和类似工具的情况下取消缓冲遗留 运行 二进制文件的标准输出
How to unbuffer stdout of legacy running binary without stdbuf and similar tools
我想监控我将要启动的程序的实时输出。我试图通过将程序的输出重定向到管道然后从监视脚本读取管道来做到这一点。
./program >> apipe
然后从监控脚本
cat apipe
但是由于>>中的缓冲区,没有输出。无论如何我可以禁用这个缓冲区?我 运行 在准系统嵌入式系统 (petalinux) 上工作,所以我无法访问 unbuffer、脚本或 stdbuf 来帮助我。
我已经在另一个平台上尝试了这些脚本,其中 unbuffer 可用,它按我预期的方式工作。
有什么方法可以配置这个缓冲区,或者使用另一个二进制文件来重定向?
编辑:我无法访问我正在尝试的命令的源代码 运行。它是一个遗留的二进制文件。
如果您无法访问 stdbuf
,您不妨模拟它并 手动取消缓冲 stdout
和 gdb
(显然假设您可以访问 gdb
)。
让我们来看看stdbuf
实际是如何运作的。 stdbuf
GNU coreutils 命令基本上只是通过设置LD_PRELOAD
环境变量在用户程序中注入libstdbuf
。 (无关紧要,但为了记录,选项通过 _STDBUF_E
/_STDBUF_I
/_STDBUF_O
env vars 传递。)
然后,当 libstdbuf
is run, it calls setvbuf
libc 函数(依次执行底层系统调用)在适当的文件描述符 (stdin
/stdout
/stderr
) 上时,使用适当的模式(完全缓冲、行缓冲或无缓冲)。
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 "" -ex "call setvbuf(stdout, 0, 2, 0)" --batch
然后,我们可以这样称呼它:
$ ./unbuffer-stdout.sh "$(pgrep -f my-program-name)"
(您可能需要 sudo
到 运行 为 root
。)
测试
我们可以使用这个带有缓冲标准输出的简单 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)"
我想监控我将要启动的程序的实时输出。我试图通过将程序的输出重定向到管道然后从监视脚本读取管道来做到这一点。
./program >> apipe
然后从监控脚本
cat apipe
但是由于>>中的缓冲区,没有输出。无论如何我可以禁用这个缓冲区?我 运行 在准系统嵌入式系统 (petalinux) 上工作,所以我无法访问 unbuffer、脚本或 stdbuf 来帮助我。
我已经在另一个平台上尝试了这些脚本,其中 unbuffer 可用,它按我预期的方式工作。
有什么方法可以配置这个缓冲区,或者使用另一个二进制文件来重定向?
编辑:我无法访问我正在尝试的命令的源代码 运行。它是一个遗留的二进制文件。
如果您无法访问 stdbuf
,您不妨模拟它并 手动取消缓冲 stdout
和 gdb
(显然假设您可以访问 gdb
)。
让我们来看看stdbuf
实际是如何运作的。 stdbuf
GNU coreutils 命令基本上只是通过设置LD_PRELOAD
环境变量在用户程序中注入libstdbuf
。 (无关紧要,但为了记录,选项通过 _STDBUF_E
/_STDBUF_I
/_STDBUF_O
env vars 传递。)
然后,当 libstdbuf
is run, it calls setvbuf
libc 函数(依次执行底层系统调用)在适当的文件描述符 (stdin
/stdout
/stderr
) 上时,使用适当的模式(完全缓冲、行缓冲或无缓冲)。
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 "" -ex "call setvbuf(stdout, 0, 2, 0)" --batch
然后,我们可以这样称呼它:
$ ./unbuffer-stdout.sh "$(pgrep -f my-program-name)"
(您可能需要 sudo
到 运行 为 root
。)
测试
我们可以使用这个带有缓冲标准输出的简单 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)"