【问题标题】:bash: force exec'd process to have unbuffered stdoutbash:强制执行的进程具有无缓冲的标准输出
【发布时间】:2011-03-20 21:50:37
【问题描述】:

我有一个类似的脚本:

#!/bin/bash
exec /usr/bin/some_binary > /tmp/my.log 2>&1

问题是some_binary 将其所有日志记录发送到标准输出,并且缓冲使我只能看到几行块的输出。当某些事情卡住时,这很烦人,我需要看看最后一行的内容。

在我执行会影响 some_binary 的 exec 之前,有什么方法可以使 stdout 无缓冲,以便它有更有用的日志记录?

(包装脚本只是在exec之前设置了几个环境变量,所以在perl或python中的解决方案也是可行的。)

【问题讨论】:

  • 丹尼斯的回答完全正确。这就是为什么。 Unix 上使用 C stdio 输出的程序将在输出不进入终端时进行缓冲(大大提高性能),除非使用setvbuf 告知不要这样做;几乎没有人为此烦恼。 expect 系统(其中unbuffer 是一个微不足道的应用程序)使用带有 Unix 伪终端设备 (ptys) 的黑魔法来运行带有不是真正终端的终端的程序,这样包装的程序就不会缓冲它的输出。这很聪明,但请注意:大多数系统只有有限数量的 pty;自然无缓冲的程序更好。
  • 顺便说一句,这在 Windows 上效果不佳。那是因为在那个平台上的 expect 使用调试魔法而不是终端魔法(因为这是 Windows 非常不同的领域)。
  • 谢谢。我决定选择修改some_binary 来做正确的事,而不是依赖黑魔法。 expect 很棒,但我不想在这里...

标签: bash logging exec unbuffered-output


【解决方案1】:

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

【讨论】:

【解决方案2】:

一些命令行程序可以选择修改其标准输出流缓冲行为。如果 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);

除了使用 expect 的 unbuffer 脚本或修改程序的源代码之外,您还可以尝试使用 script(1) 来避免管道引起的 stdout 打嗝:

见:Trick an application into thinking its stdin is interactive, not a pipe

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

# FreeBSD, Mac OS X
script -q /dev/null "[executable string]"

【讨论】:

  • 在 Mac OS X 上,因为“脚本”可能会将返回码从“\n”更改为“\r\n”,所以我需要这样运行:script -q /dev/null commands... | perl -pe 's/\n/\r\n/g'
【解决方案3】:

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

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

如果您不想通过unbuffer 命令向expect 引入依赖关系,这种方式可能更可取。另一方面,unbuffer 方式是必要的,如果你不得不欺骗 some_binary 使其认为它正面临一个真正的 tty 标准输出。

【讨论】:

    【解决方案4】:

    GNU Coreutils-8 包含一个名为 stdbuf 的程序,它本质上执行 LD_PRELOAD 技巧。它适用于 Linux,据报道适用于 BSD 系统。

    【讨论】:

      【解决方案5】:

      我在互联网上搜索了答案,但对于 uniq 来说这些都不起作用,因为它太固执,无法缓冲除了 stdbuf 之外的所有内容:

      {piped_command_here} | stdbuf -oL uniq | {more_piped_command_here}

      【讨论】:

        【解决方案6】:

        环境变量可以设置终端IO模式为无缓冲。

        导出 NSUnbufferedIO=YES

        这将为 C 和 Ojective-C 终端输出命令设置终端无缓冲。

        【讨论】:

          猜你喜欢
          • 2012-07-05
          • 1970-01-01
          • 2010-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多