将 stdout + stderr 发送到文件,并将 stderr + 任意状态消息发送到控制台

Send stdout + stderr to file, AND send stderr + arbitrary status messages to console

我在 SO 中搜索了大约 20 个问题,寻找解决这个问题的方法,但没有成功。这似乎是一项常见的任务。

我对 bash 脚本有以下要求:

  1. stdout 发送到 log.out,而不是控制台
  2. stderr 发送到 log.out 并发送到控制台
  3. 向控制台发送任意状态消息(以及 log.out?)

目前我正在尝试以下方法来实现这一点:

#!/bin/bash

> log.out

exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' 0 1 2 3
exec 1>>log.out 2>&1

# Test
echo "status goes to console" >&3
echo "stderr goes to file + console" >&2
echo "stdout goes to file"

我对这段代码的理解大概是...

  1. 将 stdout 备份到 FD 3,将 stderr 备份到 FD 4
  2. 在脚本退出时重置它们(也许没有必要?)
  3. 将 stdout 发送到 log.out,并将 stderr 也发送到那里

除了错误不会显示到控制台外,这非常有效。

所以,我想,我会在一个单独的 bg 进程中将 /dev/stderr 猫到 &3,并在第二个 exec:

下添加这一行
cat /dev/stderr >&3 &

我不明白为什么,但是,这也会将标准输出发送到 &3,所以我的控制台显示:

echoes goes to console
stderr goes to file + console
stdout goes to file

我已经尝试了大约 50 种组合,但都没有成功。经过大量阅读后,我倾向于需要一个(自定义?)C 程序或类似程序来实现这一点,这对我来说似乎有点疯狂。

非常感谢任何帮助。


谢谢!

嘿,感谢@charles-duffy 的评论和回答,我能够对我现有的脚本进行非常小的修改,从而实现了我正在寻找的内容的总体思路:

exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' 0 1 2 3
exec 1>log.out 2> >(tee /dev/tty >&1)

缺点是消息在日志文件中确实出现乱序。

假设您有 bash 4.1 或更高版本:

# make copies of orig stdout, /dev/tty, and our log file FDs
exec {orig_stdout_fd}>&1
exec {tty_fd}>/dev/tty
exec {file_fd}>log.out

# ...and set them up however you wish, using ''tee'' for anything that goes two places
exec >&$file_fd                                  # redirect stdout only to the log file
exec 2> >(tee /dev/fd/"$tty_fd" >&$file_fd)      # redirect stderr to both sinks

请注意,写入 stderr 将比写入 stdout 花费更长的时间(因为它们通过 FIFO),因此顺序可能会丢失。