orl*_*ade 1 bash io-redirection
我熟悉在bash中运行它们时管道和重定向各个进程的IO的能力.但是,有没有办法重定向stdio进行整个bash会话?
理想情况下,我想透明管所有stdout和stderr通过bash的衍生到的所有过程的tee复制到文件中显示给用户的打印输出.无论在该bash会话中运行什么进程,我都可以稍后返回并查看输出.
更理想的情况是,对于从stdin获取选项的简单交互式程序应该是这种情况,但对于像vim这样的高度交互式程序则不行.
到目前为止我发现的最好的是:每当用户打开一个新终端时,运行命令:
bash --login -i > >(tee ~/bash_$$.log) 2>&1
Run Code Online (Sandbox Code Playgroud)
这将立即开始在新的shell的交互式子shell,以及tee所有stdin和stderr一个新的父shell的PID命名的日志文件(以避免覆盖).
这有效,但vim未能开始Vim: Warning: Output is not to a terminal.有没有任何已知的解决方案,包括修补shell,这样做?
背景:vim失败,因为isatty()在给定stdout的文件描述符时返回false; 这是防止诸如vim >file通常没有意义的用途的安全措施.(此外,还有可用于与PTY交互的操作系统调用,这对于图形化,面向游标的程序非常有用,这些程序不能通过简单的FIFO实现;这就是为什么工具ssh在交互式使用期间提供伪终端的麻烦) .
对于您的目的而言重要的vim是直接检查它作为stdout传递的文件描述符.shell不是它的一方 - 它实际上是vim运行标准C库调用,它获取有关打开文件描述符的一些细节 - 因此修补或重新配置shell无法修复.
为避免这种情况,您需要找到一种不同的方法来重定向输出以进行日志记录,以便stdout和stderr仍指向PTY.
也就是说,对于你的真实目标(记录所有活动,vs对地重定向stdout),你想要的可能是script:
if [ -z "$redirection_done" ]; then
redirection_done=1 exec script shell.log bash --login -i
fi
Run Code Online (Sandbox Code Playgroud)
使用来自模拟TTY的其他工具(例如screen或)的日志记录支持tmux也同样足够.(unbuffer,从expect工具包中,可以使用具有类似效果).
回到你的文字问题......(因为它可能不是你想知道的,这是你问的):
在所有POSIX shell中,包括bash,
exec >wherever
Run Code Online (Sandbox Code Playgroud)
...将立即将当前shell的stdout重定向到wherever.这可以是bash中的进程替换,就像其他任何地方一样; 因此,在已经运行的shell中,您可以执行
exec > >(tee shell.log) 2>&1
Run Code Online (Sandbox Code Playgroud)