程序终止时Bash保存/重定向stdout和stderr

程序终止时Bash保存/重定向stdout和stderr,bash,redirect,stdout,Bash,Redirect,Stdout,当外部进程(killed:9)终止ProgramA时,我无法重定向其输出(std/stderr)或将其保存到变量 方案A: $ ./ProgramA arg1 This is on stderr This is on stdout Killed: 9 未能保存到变量: $ ProgramA_Output=`ProgramA arg1` $ echo "$ProgramA_Output" $ 重定向到文件也不起作用: $ ProgramA arg1 > output.txt

当外部进程(killed:9)终止ProgramA时,我无法重定向其输出(std/stderr)或将其保存到变量

方案A:

$ ./ProgramA arg1
  This is on stderr
  This is on stdout
  Killed: 9
未能保存到变量:

$ ProgramA_Output=`ProgramA arg1`
$ echo "$ProgramA_Output"

$
重定向到文件也不起作用:

$ ProgramA arg1 > output.txt
$ cat ./output.txt
$

有没有保存/重定向输出的线索?

最可能的直接原因是,当输出为TTY时,您的程序仅逐行刷新其缓冲区;因此,当重定向到文件或FIFO时,当SIGKILL被传递时,它还没有刷新——并且由于SIGKILL不能被捕获或延迟,所以在那个时候它没有机会执行刷新

如果您在GNU平台上,默认情况下可以使用
stdbuf
修改此行为:

stdbuf -o0 ./ProgramA arg1 >output.txt
……或者

output=$(stdbuf -o0 ./ProgramA arg1)
因为您知道当输出到tty时它会刷新(因为在没有重定向的情况下运行时输出会立即显示),所以您也可以使用
unbuffer
(随
expect
附带的工具)来模拟该效果:

output=$(unbuffer ./ProgramA arg1)


但是,最可靠的方法是修改
ProgramA
的源代码,以便在每次写入完成后显式执行刷新操作,并且仅在绝对需要时使用SIGKILL。(一种常见的做法是使用SIGTERM,等待相当长的一段时间,然后才使用SIGKILL)。

如果是外壳本身被杀死,则不能对SIGKILL执行任何操作。这就是使用它而不是SIGTERM的全部意义(相反,只要可能,也就是使用SIGTERM):它不能被捕获/处理,因此保证立即完成[阻止系统调用或类似操作],但也保证不会让被杀死的程序自行清理、刷新其输出缓冲区,也就是说,你是否编写了
程序a
?如果是这样的话,你可以强迫它提前刷新它的缓冲区。不幸的是,我没有编写
ProgramA
,我甚至不知道是什么导致它被杀死。好吧,找出这个是一个好的开始。如果您使用的是Linux,我建议您检查
dmesg
,看看它是否是OOM杀手;如果不是这样,
sysdig
是一个工具,它可以简单地告诉您操作系统上的哪个进程正在发送信号。