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

时间:2018-08-14 15:44:39

标签: bash shell stdout stderr io-redirection

我在整个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 &

我不明白为什么,但是,这也会将stdout发送到&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)

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

1 个答案:

答案 0 :(得分: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),因此可能会丢失顺序。