在一个脚本中将bash输出(stderr和stdout)一次记录到多个文件中

在一个脚本中将bash输出(stderr和stdout)一次记录到多个文件中,bash,exec,file-descriptor,Bash,Exec,File Descriptor,假设您有一个bash脚本,并且希望打印并将输出(stderr和stdout)保存到日志文件中。基于这个答案:@cdarke,这就是你可以做到的 #/bin/bash exec>>(tee my.log)2>&1 回音“你好” 但是,如果您有一个脚本,其中不同的部分需要转到不同的日志文件,该怎么办?假设您想将典型的配置,生成,生成测试分别输出到各自的日志文件中?天真的方法可能是这样的(为了简单起见,这里的configure和echos类似): #/bin/bash #清除日志 rm-f conf

假设您有一个bash脚本,并且希望打印并将输出(stderr和stdout)保存到日志文件中。基于这个答案:@cdarke,这就是你可以做到的

#/bin/bash
exec>>(tee my.log)2>&1
回音“你好”
但是,如果您有一个脚本,其中不同的部分需要转到不同的日志文件,该怎么办?假设您想将典型的
配置
生成
生成测试
分别输出到各自的日志文件中?天真的方法可能是这样的(为了简单起见,这里的
configure
echo
s类似):

#/bin/bash
#清除日志
rm-f configure.log make.log make_test.log
exec>>(tee configure.log)2>&1
回显“配置”
exec>>(tee make.log)2>&1
回声“制造”
exec>>(tee make_test.log)2>&1
回声“做测试”
但是当您执行此脚本时,您会注意到只有最后一个输出包含它应该包含的内容:

$ tail *.log
==> configure.log <==
configure
make
make test

==> make.log <==
make
make test

==> make_test.log <==
make test
以下是生成的日志文件:

$ tail *.log
==> configure.log <==
configure

==> make.log <==
make

==> make_test.log <==
make test

==> tmp.log <==
$tail*.log

==>configure.log make.log make_test.log tmp.log原因是,您在对
exec
的每次调用中复制标准输出文件描述符,导致您从所有三个
echo
调用中输出所有三个文件。i、 e.在设置初始的
exec
之后

exec > >(tee make.log) 2>&1
echo "make"
最近的echo'd语句不仅会转到
make.log
,还会转到
configure.log
,因为您以前的
exec
设置了对该日志文件的写入,以从stdout获取内容。现在,第一个日志文件包含两个echo语句中的行。在您的下一个案例中,这也会再次复制

为避免此问题,请为每个独特的情况设置不同的文件描述符,即

exec 3> >(tee configure.log) 2>&1
echo "configure" >&3

exec 4> >(tee make.log) 2>&1
echo "make" >&4

exec 5> >(tee make_test.log) 2>&1
echo "make test" >&5

# Releasing the file descriptors back to shell
exec 3>&-
exec 4>&-
exec 5>&-
或者,如果您使用的是bash版本>4.1,则可以让shell为您分配文件描述符,这样您就不必显式地选择数字

exec {fd1}> >(tee configure.log) 2>&1
echo "configure" >&"$fd1"

exec {fd2}> >(tee make.log) 2>&1
echo "make" >&"$fd2"

exec {fd3}> >(tee make_test.log) 2>&1
echo "make test" >&"$fd3"
执行
exec{fd1}>
时,bash会自动用文件描述符(通常大于10)填充
fd1
变量。现在,您可以像以前一样在通话中使用
$fd1
tee
。如前所述,您可以通过将所使用的描述符关闭为

exec >&"$fd1"-
exec >&"$fd2"-
exec >&"$fd3"-

如果您想让stderr也转到相应的日志文件,请将重定向
2>&1
更改为打开的相应文件描述符,即

2>&3        
2>&"$fd1"