将 stdout + stderr 发送到文件,并将 stderr + 任意状态消息发送到控制台
Send stdout + stderr to file, AND send stderr + arbitrary status messages to console
我在 SO 中搜索了大约 20 个问题,寻找解决这个问题的方法,但没有成功。这似乎是一项常见的任务。
我对 bash 脚本有以下要求:
- 将
stdout
发送到 log.out
,而不是控制台
- 将
stderr
发送到 log.out
并发送到控制台
- 向控制台发送任意状态消息(以及
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"
我对这段代码的理解大概是...
- 将 stdout 备份到 FD 3,将 stderr 备份到 FD 4
- 在脚本退出时重置它们(也许没有必要?)
- 将 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),因此顺序可能会丢失。
我在 SO 中搜索了大约 20 个问题,寻找解决这个问题的方法,但没有成功。这似乎是一项常见的任务。
我对 bash 脚本有以下要求:
- 将
stdout
发送到log.out
,而不是控制台 - 将
stderr
发送到log.out
并发送到控制台 - 向控制台发送任意状态消息(以及
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"
我对这段代码的理解大概是...
- 将 stdout 备份到 FD 3,将 stderr 备份到 FD 4
- 在脚本退出时重置它们(也许没有必要?)
- 将 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),因此顺序可能会丢失。