是否可以在没有TTY的情况下自动刷新STDOUT / STDERR?

时间:2017-01-27 17:53:45

标签: linux bash

我有一个名为批处理启动器的bash脚本。它负责发布和报告各批次的状态。批次的启动是这样完成的:

env $BENV setsid $BATCH $OPT >> $FILE 2>&1

几个月前,我遇到了一个问题,一个带有分叉子项的批处理器在PGID上发送了一个kill信号,最终杀死了批处理器和批处理启动器,这是一个很大的禁忌。我对这个问题的解决方案是添加setsid部分(因为bash不允许setpgrp),这会创建一个新会话,结果是一个新的PGID。

现在我有另一个问题。除了孩子们在完成工作之前没有写任何日志,那与分叉孩子一样的讨厌批处理。调查问题之后,我发现原因here - setsid生成一个没有TTY的进程,在这种情况下,子进程的任何输出都不会在每个换行符上自动刷新,而是在每个换行符处刷新一次在关闭之前结束。这意味着如果一个孩子因错误而死亡,缓冲区中的日志将永远消失,无法进行任何调试。

有没有办法告诉setsid自动刷新STDOUT / STDERR输出流?谷歌搜索这个没有结果,此时我唯一的解决方案是用支持setpgrp的语言(如PERL或C)重写批处理启动器,这需要从QA进行大量测试。

修改

小调,问题可以通过以下方式解决:

env $BENV script -qec "$BATCH $OPT" -af $FILE

这要求早于2010年的util-linux支持-e标志以进行返回代码处理(遗憾的是,对于我来自2005年的RHEL5,情况并非如此,有关详细信息,请参阅commit)。< / p>

1 个答案:

答案 0 :(得分:1)

添加stdbuf -o0(无缓冲,或stdbuf -oL线缓冲)

env $BENV setsid stdbuf -o0 $BATCH $OPT >> $FILE 2>&1

应该解决问题(只要通过libc的stdio和libc的$ BATCH缓冲区动态链接(默认))。

编辑:

这是一个快速的“stdbuf -o0仿真:

#!/bin/sh -e
trap 'rm -rf "$tmpd"' EXIT HUP INT QUIT TERM
tmpd=$(mktemp -d)
cat > "$tmpd/unbuf.c" <<EOF
#include <stdio.h>
__attribute__((constructor))
static void unbuffer(void){ setvbuf(stdout, 0, _IONBF, 0); }
EOF
gcc "$tmpd/unbuf.c" -o "$tmpd/unbuf.so" -fpic -shared
LD_PRELOAD="$tmpd/unbuf.so" "$@"