stdbuf 不工作,而 unbuffer 工作

stdbuf 不工作,而 unbuffer 工作

我正在尝试将时间戳应用于标准输出进程的时间戳。为了应用正确的时间戳,我尝试unbuffer 标准输出进程。这适用于,unbuffer但不符合stdbuf我的预期。考虑以下慢速打印脚本'慢速打印':

#!/bin/bash

if [ $# -ne 2 ]; then
   echo "usage: ${0%%/*} <file> <delay in microseconds>"
   exit 1
fi

DELAY=$2 perl -pe 'BEGIN{use Time::HiRes qw(usleep)} { usleep($ENV{DELAY}) }' $

现在比较以下应用时间戳的尝试:

stdbuf -oL ./slowprint <(ls) 100000 | 
awk '{ print strftime("%H:%M:%S"), $0; fflush(); }'

对比

unbuffer ./slowprint <(ls) 100000 | 
awk '{ print strftime("%H:%M:%S"), $0; fflush(); }' 

第二个对我来说有效,而第一个则无效,尽管我希望它们能做同样的事情。目前unbuffer不适合,因为它在某些情况下会吞掉错误代码,(我发布了关于该行为的另一个问题)。

答案1

尝试annotate-output. 它提供时间戳标准输入标准输出, 和标准错误

例如,用来wcbash 流程替代,(一行)以及不存在的文件:

annotate-output wc -l <(echo foo) nosuchfile

输出:

10:17:45 I: Started wc -l /dev/fd/63 nosuchfile
10:17:45 O:       1 /dev/fd/63
10:17:45 E: wc: nosuchfile: No such file or directory
10:17:45 O:       1 total
10:17:45 I: Finished with exitcode 1

答案2

我认为差异在于底层机制:

  • stdbuf使用 LD_PRELOAD 加载使用__attribute__((constructor))其中函数注释的共享库,从而运行该函数的代码main。该函数依次使用setvbuflibc 的功能来配置用于的缓冲区stdinstdout以及stderr 启动时.没有什么可以阻止应用程序撤消因为它有自己的setvbuf-ing。我相信perl它有自己的 -ing,这就是为什么你使用的 -ingstdbuf被忽略了。

  • unbuffer以不同的方式工作 - 它使用内核创建一个伪tty,从而使应用程序认为它的标准输出isatty;因此 libc 的行为默认为行缓冲输出。

相关内容