我有一个名为批处理启动器的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>
答案 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" "$@"