我正在尝试将时间戳应用于标准输出进程的时间戳。为了应用正确的时间戳,我尝试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
. 它提供时间戳标准输入,标准输出, 和标准错误。
例如,用来wc
对bash
流程替代,(一行)以及不存在的文件:
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。该函数依次使用setvbuf
libc 的功能来配置用于的缓冲区stdin
,stdout
以及stderr
启动时.没有什么可以阻止应用程序撤消因为它有自己的setvbuf
-ing。我相信perl
它有自己的 -ing,这就是为什么你使用的 -ingstdbuf
被忽略了。unbuffer
以不同的方式工作 - 它使用内核创建一个伪tty,从而使应用程序认为它的标准输出isatty
;因此 libc 的行为默认为行缓冲输出。