将整个bash会话重定向到日志文件

时间:2016-08-07 02:17:02

标签: bash io-redirection

我熟悉在bash中运行时管道和重定向各个进程的IO的能力。但是,有没有办法将stdio重定向到整个bash会话?

理想情况下,我希望将bash生成的所有进程的stdoutstderr透明地传输到tee,以将显示给用户的打印输出复制到文件中。无论在该bash会话中运行什么进程,我都可以稍后返回并查看输出。

更理想的情况是,对于从stdin获取选项的简单交互式程序应该是这种情况,但对于像vim这样的高度交互式程序则不行。

到目前为止我发现的最好的是:每当用户打开一个新终端时,运行命令:

bash --login -i > >(tee ~/bash_$$.log) 2>&1

这将立即在该新shell中启动交互式子shell,并tee将所有stdinstderr添加到以新父shell的PID命名的日志文件中(以避免覆盖)。

这样可行,但vim无法以Vim: Warning: Output is not to a terminal开头。是否有任何已知的解决方案,包括修补shell,以实现此目的?

1 个答案:

答案 0 :(得分:5)

后台 vim失败,因为isatty()在给定stdout的文件描述符时返回false;这是防止vim >file等通常没有意义的用途的安全措施。 (此外,还有可用于与PTY交互的操作系统调用,这对于图形,面向游标的程序非常有用,这些程序不能通过简单的FIFO实现;这就是为什么像ssh这样的工具会遇到麻烦来提供互动使用期间的伪终端)。

对于您的目的,重要的是 vim直接检查它作为stdout 传递的文件描述符。 shell不是它的一方 - 它实际上是vim运行标准C库调用,它获取有关打开文件描述符的一些细节 - 所以修补或重新配置shell无法修复。

为避免这种情况,您需要找到一种不同的方法来重定向输出以进行日志记录,以便stdout和stderr仍指向PTY。

那就是说,对于你的真正的目标(记录所有活动,而不是就地重定向stdout),你想要的可能是script

if [ -z "$redirection_done" ]; then
  redirection_done=1 exec script shell.log bash --login -i
fi

使用来自模拟TTY的其他工具(例如screentmux)的日志记录支持也足够了。 (unbuffer工具包中的expect可以使用类似的效果。)

回到您的文字问题...... (因为虽然它可能不是您想知道的,但它 你问的是什么):

在所有POSIX shell中,包括bash,

exec >wherever

...会立即将当前shell的stdout重定向到wherever。这可以是bash中的进程替换,就像其他任何地方一样;因此,在已经运行的shell中,您可以执行

exec > >(tee shell.log) 2>&1