更新:我认为下面的代码可能朝着错误的方向发展——但问题仍然存在,我是否可以打开一个管道来记录所有输出(文件和控制台(,暂停该日志并记录到一个新日志(新文件和控制台(中,然后通过移动FD而不重新打开原始日志文件来重新连接到原始记录器的FD
试图在bash中提高我对FD的了解。我试图记录主"元"test.sh
的所有输出,但当我进入"部分"时,会记录到另一个文件,例如函数、源脚本等。然后返回到"元"日志的附件。
我知道我可以用子shell很容易地实现这一点——或者通过再次打开"meta"日志并从那里进行附加,但有人能通过切换FD来帮助实现这一目标吗?
#!/bin/bash
rm *.log
NAMED_PIPE="$(mktemp -u /tmp/pipe.XXXX)"
mknod $NAMED_PIPE p
tee <$NAMED_PIPE "./meta.log" &
section () {
echo SECTION: stdout
echo SECTION: stderr >&2
}
# link stdout->3 & stderr->4 and save stdout & stderr
exec 3>&1 4>&2 &> "$NAMED_PIPE"
echo METAstr: stdout
echo METAstr: stderr >&2
# restore stdout & stderr
exec 1>&3 2>&4
# sleep 1 # I think an additional delay prevents the possible race condition I'm seeing
# exec 1>&3- 2>&4- ... I think this would restore but close 3 & 4?
# do I need another named pipe here?
section 2>&1 # | tee section.log
# re-link to same pipe
exec 3>&1 4>&2 &> "$NAMED_PIPE"
echo METAend: stdout
echo METAend: stderr >&2
在不尝试记录"节"的情况下,所有的元输出都会在脚本返回后打印出来:
-bash-4.2# ./test.sh
SECTION: stdout
SECTION: stderr
-bash-4.2# METAstr: stdout
METAstr: stderr
METAend: stdout
METAend: stderr
我认为试图记录"部分"会污染我的FD,所以下面的高管挂断了我的电话:
-bash-4.2# ./test.sh
METAstr: stdout
METAstr: stderr
SECTION: stdout
SECTION: stderr
第1版:
在未尝试tee section
:的情况下运行脚本后meta.log
的内容
[root@master tmp]# cat meta.log
METAstr: stdout
METAstr: stderr
METAend: stdout
METAend: stderr
它记录结束消息,tee
在脚本完成之前不会退出
第2版:EDIT1的修订版。我认为这是比赛条件。我认为FD正在关闭,但在最后的回显命令发生时,它们还没有关闭。
我本来打算写同样的东西。这是比赛条件。第二个exec关闭进程中的写入端,向tee发出EOF信号。当发球台得到EOF时,发球台会想退出。如果在您调用最后一个exec时它确实退出了,那么最后一个exec将阻塞。如果此时它还没有退出,它将不会阻塞,因为FIFO的读取端仍然是打开的。
任何延迟都会使发球台更有可能在那个时候退场。孕育一个过程使它很有可能。我发现stracing(这会使程序稍微慢一点(大约是50/50。