我熟悉在bash中运行时管道和重定向各个进程的IO的能力。但是,有没有办法将stdio重定向到整个bash会话?
理想情况下,我希望将bash生成的所有进程的stdout
和stderr
透明地传输到tee
,以将显示给用户的打印输出复制到文件中。无论在该bash会话中运行什么进程,我都可以稍后返回并查看输出。
更理想的情况是,对于从stdin获取选项的简单交互式程序应该是这种情况,但对于像vim这样的高度交互式程序则不行。
到目前为止我发现的最好的是:每当用户打开一个新终端时,运行命令:
bash --login -i > >(tee ~/bash_$$.log) 2>&1
这将立即在该新shell中启动交互式子shell,并tee
将所有stdin
和stderr
添加到以新父shell的PID命名的日志文件中(以避免覆盖)。
这样可行,但vim
无法以Vim: Warning: Output is not to a terminal
开头。是否有任何已知的解决方案,包括修补shell,以实现此目的?
答案 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的其他工具(例如screen
或tmux
)的日志记录支持也足够了。 (unbuffer
工具包中的expect
可以使用类似的效果。)
回到您的文字问题...... (因为虽然它可能不是您想知道的,但它 你问的是什么):
在所有POSIX shell中,包括bash,
exec >wherever
...会立即将当前shell的stdout重定向到wherever
。这可以是bash中的进程替换,就像其他任何地方一样;因此,在已经运行的shell中,您可以执行
exec > >(tee shell.log) 2>&1