如何让Bourne Shell脚本日志同时输出至文件与控制台?
在Bourne Shell(/bin/sh)中实现日志同时输出到文件和控制台
Bash里的exec &> >(tee -a "$log")依赖进程替换(>(...)语法),但Bourne Shell(/bin/sh)不支持这个特性,需要用文件描述符或管道的方式替代。
方法一:使用命名管道(mkfifo)
这是兼容性最好的方案,几乎所有POSIX兼容的/bin/sh都支持:
#!/bin/sh log="mylog.log" # 创建临时命名管道 log_pipe="/tmp/$(basename "$0").pipe" mkfifo "$log_pipe" # 启动tee:从管道读取内容,同时追加到日志文件并输出到控制台 tee -a "$log" < "$log_pipe" & tee_pid=$! # 将当前Shell的标准输出和标准错误都重定向到管道 exec > "$log_pipe" 2>&1 # 脚本退出时自动清理管道和tee进程 trap 'kill "$tee_pid" 2>/dev/null; rm -f "$log_pipe"' EXIT
说明:
mkfifo创建命名管道,作为Shell输出和tee的中转通道- 后台启动的
tee从管道读取内容,同时完成日志追加和控制台输出 exec > "$log_pipe" 2>&1把当前Shell的所有输出(包括标准错误)都定向到管道trap语句确保脚本退出时清理临时文件和后台进程,避免残留垃圾
方法二:使用文件描述符复制
如果不想创建临时文件,也可以通过文件描述符复制实现:
#!/bin/sh log="mylog.log" # 保存原始的标准输出(fd1)到fd3,标准错误(fd2)到fd4 exec 3>&1 4>&2 # 启动tee:读取标准输入,同时写入日志和原始控制台,错误输出转原始标准错误 tee -a "$log" >&3 2>&4 & tee_pid=$! # 将当前Shell的标准输出和错误都重定向到tee的标准输入 exec >&0 2>&1 # 退出时清理tee进程 trap 'kill "$tee_pid" 2>/dev/null' EXIT
说明:
- 先保存原始控制台的输出描述符,避免
tee无法输出到控制台 - 后台运行的
tee负责将输入内容同时写入日志和原始控制台 - 最后把Shell的所有输出重定向到
tee的输入,实现双端输出
内容的提问来源于stack exchange,提问作者flymg
相关产品推荐
相关产品推荐

