我知道如何重定向标准输出到一个文件:

exec > foo.log
echo test

这将把“test”放到foo.log文件中。

现在我想将输出重定向到日志文件中,并将其保持在stdout

也就是说,它可以在脚本之外简单地完成:

script | tee foo.log

但我想在脚本中声明它

我试着

exec | tee foo.log

但这并没有起作用。


当前回答

这两种方法都不是完美的解决方案,但你可以尝试以下几件事:

exec >foo.log
tail -f foo.log &
# rest of your script

or

PIPE=tmp.fifo
mkfifo $PIPE
exec >$PIPE
tee foo.log <$PIPE &
# rest of your script
rm $PIPE

如果你的脚本出了问题,第二种方法会留下一个管道文件,这可能是问题,也可能不是问题(例如,也许你可以随后在父shell中rm它)。

其他回答

使用已接受的答案,我的脚本总是异常早地返回(就在'exec > >(tee…)'之后),让我的脚本的其余部分在后台运行。由于我无法以我的方式得到解决方案,我找到了另一个解决方案/解决问题:

# Logging setup
logfile=mylogfile
mkfifo ${logfile}.pipe
tee < ${logfile}.pipe $logfile &
exec &> ${logfile}.pipe
rm ${logfile}.pipe

# Rest of my script

这使得脚本的输出从进程出发,通过管道进入'tee'的子后台进程,该进程将所有内容记录到磁盘和脚本的原始标准输出。

注意'exec &>'同时重定向stdout和stderr,如果我们愿意,我们可以分别重定向它们,或者如果我们只想要stdout,则更改为'exec >'。

即使管道在脚本开始时从文件系统中删除,它仍将继续工作,直到进程完成。我们只是不能在rm行之后使用文件名引用它。

使bash脚本日志转换为syslog的简单方法。脚本输出可以通过/var/log/syslog和stderr获得。Syslog将添加有用的元数据,包括时间戳。

在顶部添加这一行:

exec &> >(logger -t myscript -s)

或者,将日志发送到一个单独的文件:

exec &> >(ts |tee -a /tmp/myscript.output >&2 )

这需要更多的utils(用于ts命令,它添加时间戳)。

这两种方法都不是完美的解决方案,但你可以尝试以下几件事:

exec >foo.log
tail -f foo.log &
# rest of your script

or

PIPE=tmp.fifo
mkfifo $PIPE
exec >$PIPE
tee foo.log <$PIPE &
# rest of your script
rm $PIPE

如果你的脚本出了问题,第二种方法会留下一个管道文件,这可能是问题,也可能不是问题(例如,也许你可以随后在父shell中rm它)。

在你的脚本文件中,把所有的命令都放在括号里,就像这样:

(
echo start
ls -l
echo end
) | tee foo.log

不能说我对任何基于exec的解决方案都感到满意。我更喜欢直接使用tee,所以我在请求时使用tee调用脚本本身:

# my script: 

check_tee_output()
{
    # copy (append) stdout and stderr to log file if TEE is unset or true
    if [[ -z $TEE || "$TEE" == true ]]; then 
        echo '-------------------------------------------' >> log.txt
        echo '***' $(date) $0 $@ >> log.txt
        TEE=false $0 $@ 2>&1 | tee --append log.txt
        exit $?
    fi 
}

check_tee_output $@

rest of my script

这允许你这样做:

your_script.sh args           # tee 
TEE=true your_script.sh args  # tee 
TEE=false your_script.sh args # don't tee
export TEE=false
your_script.sh args           # tee

你可以自定义它,例如让tee=false作为默认值,让tee保存日志文件,等等。我想这个解决方案与jbarlow的类似,但是更简单,也许我的解决方案有我还没有遇到的局限性。