bash:强制exec'd进程有无缓冲的stdout

bst*_*rre 20 bash logging exec unbuffered-output

我有一个像这样的脚本:

#!/bin/bash
exec /usr/bin/some_binary > /tmp/my.log 2>&1
Run Code Online (Sandbox Code Playgroud)

问题是它将some_binary所有日志记录发送到stdout,并且缓冲使得它只能看到几行的块输出.当一些事情陷入困境时,这很烦人,我需要看看最后一行说的是什么.

有没有办法让stdout在我执行会影响some_binary的exec之前没有缓冲,所以它有更多有用的日志记录?

(包装器脚本只在exec之前设置一些环境变量,因此perl或python中的解决方案也是可行的.)

小智 28

GNU coreutils-8.5还具有stdbuf修改I/O流缓冲的命令:

http://www.pixelbeat.org/programming/stdio_buffering/

因此,在您的示例中,只需调用:

stdbuf -oL /usr/bin/some_binary > /tmp/my.log 2>&1
Run Code Online (Sandbox Code Playgroud)

这将允许文本逐行显示(一旦完成一行"\n"与C 中的行尾字符).如果您真的想立即输出,请-o0改用.

如果您不想将依赖项引入expectvia unbuffer命令,则可能更希望这种方式.unbuffer另一方面,如果你不得不愚蠢some_binary地认为它面临着真正的标准输出,那么这种方式是必要的.


Pau*_*ce. 13

您可能会发现unbuffer附带的脚本expect可能会有所帮助.


小智 11

某些命令行程序可以选择修改其stdout流缓冲行为.如果C源可用,那就是要走的路......

# two command options ...
man file | less -p '--no-buffer'
man grep | less -p '--line-buffered'

# ... and their respective source code

# from: http://www.opensource.apple.com/source/file/file-6.2.1/file/src/file.c
if(nobuffer)
   (void) fflush(stdout);

# from: http://www.opensource.apple.com/source/grep/grep-28/grep/src/grep.c
if (line_buffered)
   fflush (stdout);
Run Code Online (Sandbox Code Playgroud)

作为使用expect的unbuffer脚本或修改程序源代码的替代方法,您也可以尝试使用脚本(1)来避免由管道引起的stdout打嗝:

请参阅:欺骗应用程序,使其认为其标准输入是交互式的,而不是管道

# Linux
script -c "[executable string]" /dev/null

# FreeBSD, Mac OS X
script -q /dev/null "[executable string]"
Run Code Online (Sandbox Code Playgroud)