问题描述
我想监视我将要启动的程序的实时输出.我试图通过将程序的输出重定向到管道,然后从监视脚本读取管道来做到这一点.
I want to monitor the realtime output of a program that I will start. I am trying to do this by redirecting the output of the program to a pipe and then reading the pipe from a monitoring script.
./program >> apipe
然后从监视脚本中
cat apipe
但是,由于>>中的缓冲区,因此没有输出.无论如何,我可以禁用此缓冲区?我在准系统嵌入式系统(petalinux)上运行,因此无法访问unbuffer,脚本或stdbuf来帮助我.
However due to the buffer in >> there is no output. Anyway I can disable this buffer? I am running on a barebones embedded system (petalinux) so I don't have access to unbuffer, script, or stdbuf to help me out.
我在另一个可以使用unbuffer的平台上尝试了这些脚本,它按我的预期工作.
I have tried the scripts on another platform where unbuffer is available it works as I expect.
可以通过任何方式配置此缓冲区,或使用其他二进制文件进行重定向吗?
Any way I can configure this buffer, or use another binary to redirect?
我无权访问我要运行的命令的源代码.这是旧版二进制文件.
I do not have access to the source code of the command I am trying to run. It is a legacy binary.
推荐答案
如果您无权访问stdbuf
,则可以对其进行模拟并使用手动取消缓冲stdout
gdb
(假设您显然可以访问gdb
).
If you don't have access to stdbuf
, you might as well simulate it and unbuffer the stdout
manually with gdb
(assuming obviously you have access to gdb
).
让我们看一下stdbuf
的实际运行方式. stdbuf
GNU coreutils命令基本上只注入LD_PRELOAD环境变量>>. (这不重要,但为了记录起见,选项是通过_STDBUF_E
/_STDBUF_I
/_STDBUF_O
env vars传递的.)
Let's take a look at how stdbuf
actually operates. The stdbuf
GNU coreutils command basically only injects libstdbuf
in the user program by setting LD_PRELOAD
environment variable. (Irrelevant, but for the record, options are passed via _STDBUF_E
/_STDBUF_I
/_STDBUF_O
env vars.)
然后,当运行 libstdbuf
时,它会调用 setvbuf
libc函数(依次以适当的模式(完全缓冲,行缓冲或非缓冲)在适当的文件描述符(stdin
/stdout
/stderr
)上执行底层系统调用.
Then, when the libstdbuf
is run, it calls setvbuf
libc function (which in turn executes the underlaying syscall) on appropriate file descriptors (stdin
/stdout
/stderr
), with the appropriate mode (fully buffered, line buffered, or unbuffered).
setvbuf
的声明在stdio.h
中,可用于man 3 setvbuf
:
Declaration for setvbuf
is in stdio.h
, available with 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
).
Values for mode
are: _IONBF
, _IOLBF
, _IOFBF
, as defined in stdio.h
. We are here only interested in the unbuffered mode: _IONBF
. It has a value of 2
(you can check your /usr/include/stdio.h
).
因此,要为某个进程取消缓冲stdout
,我们只需要调用:
So, to unbuffer a stdout
for some process, we just need to call:
setvbuf(stdout, NULL, _IONBF, 0)
我们可以轻松地通过gdb
做到这一点.让我们编写一个可以调用的脚本unbuffer-stdout.sh
:
We can easily do that with gdb
. Let's make a script we can call, unbuffer-stdout.sh
:
#!/bin/bash
# usage: unbuffer-stdout.sh PID
gdb --pid "$1" -ex "call setvbuf(stdout, 0, 2, 0)" --batch
然后,我们可以这样称呼它:
Then, we can call it like:
$ ./unbuffer-stdout.sh "$(pgrep -f my-program-name)"
(您可能需要sudo
才能将其作为root
运行.)
(You'll probably need sudo
to run it as root
.)
我们可以将这个简单的Python程序与缓冲的标准输出(如果未通过-u
调用且未设置PYTHONUNBUFFERED
调用)一起使用,writer.py
:
We can use this simple Python program with buffered standard output (if not called with -u
, and with unset 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
观察到没有任何输出出现,直到我们运行:
and observe no output appears until we run:
$ sudo ./unbuffer-stdout.sh "$(pgrep -f writer.py)"
这篇关于如何在没有stdbuf和类似工具的情况下解缓冲旧版正在运行的二进制文件的stdout的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!