You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Bash脚本内将stdout和stderr带时间戳同时输出到控制台与文件?

看起来你碰到了一个典型的输出重定向陷阱——有些程序(比如这里的Perl)可能会绕过shell的标准stdout/stderr重定向,直接把信息写到终端设备(/dev/tty),或者你的原写法在处理输出流时存在细微问题,导致部分内容没被捕获进日志。我来给你两个可靠的解决方案:

方案一:简化重定向逻辑,统一处理stdout和stderr

把你脚本里的exec行替换成下面的写法,它能确保所有标准输出和错误都被正确捕获、加时间戳,同时输出到终端并写入日志:

exec > >(ts '[%Y-%m-%d %H:%M:%S]' | tee -a /var/log/dehydrated.log) 2>&1

逻辑说明:

  • exec > >(...):将当前shell的**标准输出(stdout)**重定向到进程替换的管道,让ts给每行内容加上时间戳,再传给tee
  • tee -a /var/log/dehydrated.log:tee会把输入同时追加到日志文件,并且默认将内容输出回终端(因为tee的标准输出就是当前终端)
  • 2>&1:将**标准错误(stderr)**重定向到和stdout相同的管道,这样stderr的内容也会经过ts加时间戳,再被tee处理

方案二:用script命令捕获所有终端输出

如果某些程序确实直接写入/dev/tty(绕过shell重定向),上面的方案可能还是抓不到。这时候可以用script命令,它能捕获所有终端相关的输出,包括直接写终端的内容:

#!/bin/bash -ex

# 避免脚本递归执行
if [ -z "$WRAPPED_BY_SCRIPT" ]; then
    export WRAPPED_BY_SCRIPT=1
    # script -q 静默模式(不显示script本身的启动/结束信息)
    # -c "$0" 执行当前脚本
    # /dev/null 避免生成默认的typescript日志文件
    script -q -c "$0" /dev/null | ts '[%Y-%m-%d %H:%M:%S]' | tee -a /var/log/dehydrated.log
    exit $?
fi

# 这里放你原来的脚本业务逻辑
...

逻辑说明:

  • 我们通过环境变量WRAPPED_BY_SCRIPT判断是否已经在script的包裹中,避免递归执行
  • script会模拟一个终端环境,捕获所有输出(包括直接写/dev/tty的内容),然后把输出传给ts加时间戳,最后用tee同时输出到终端和日志

替换完成后,再运行你的脚本,Perl的locale警告应该会同时出现在终端和日志文件中,并且每行都带有你指定的时间戳格式。

内容的提问来源于stack exchange,提问作者mles

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 16:37:51