我有一个带有大量输出的 bash 脚本,我想更改该脚本(而不是创建一个新脚本)以将所有输出复制到一个文件中,就像我通过 tee 管道传输它一样。
我有一个文件script.sh:
#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT
launch_applications_that_output_to_STDOUT
fini
Run Code Online (Sandbox Code Playgroud)
我想将 STDOUT 的副本复制到文件script.log 中,而不必./script.sh | tee script.log
每次都键入。
谢谢,汤姆
Den*_*son 27
只需将其添加到脚本的开头:
exec > >(tee -ia script.log)
Run Code Online (Sandbox Code Playgroud)
这会将发送到 stdout 的所有输出附加到 file script.log
,保留先前的内容。如果您想在每次运行脚本时重新开始,只需rm script.log
在该exec
命令之前添加或-a
从tee
命令中删除。
该-i
选项会导致tee
忽略中断信号并允许tee
捕获更完整的输出集。
添加此行以捕获所有错误(在单独的文件中):
exec 2> >(tee -ia scripterr.out)
Run Code Online (Sandbox Code Playgroud)
多个>
符号之间的空格很重要。
Chr*_*rel 16
我无法让丹尼斯的非常简单的单线工作,所以这里有一个更复杂的方法。我会先试试他的。
如前所述,您可以使用 exec 为整个脚本重定向标准错误和标准输出。像这样:
exec > $LOGFILE 2>&1
这会将所有 stderr 和 stdout 输出到 $LOGFILE。
现在,由于您希望将其显示到控制台以及日志文件,您还必须使用命名管道让 exec 写入,并使用 tee 读取。
(Dennis 的 one-liner 在技术上也是这样做的,虽然显然是以不同的方式)管道本身是用mkfifo $PIPEFILE
. 然后执行以下操作。
# 开始向日志文件写入 tee,但从我们的命名管道中提取其输入。 三通 $LOGFILE < $PIPEFILE & # 为等待命令捕获 tee 的进程 ID。 TEEPID=$! # 将其余的 stderr 和 stdout 重定向到我们的命名管道。 执行 > $PIPEFILE 2>&1 echo "在此处发出命令" 回声“他们所有的标准输出都会被发现。” echo "他们的标准错误也是如此" >&2 # 关闭 stderr 和 stdout 文件描述符。 执行 1>&- 2>&- # 等待 tee 完成,因为现在管道的另一端已经关闭。 等待 $TEEPID
如果您想要彻底,您可以在脚本的开头和结尾创建和销毁命名管道文件。
为了记录,我从一个随机的人的非常有用的博客文章中收集了大部分内容:(存档版本)
小智 7
这是丹尼斯威廉姆森早些时候发布的答案的组合版本。将 err 和 std 以正确的顺序附加到 script.log 中。
将此行添加到脚本的开头:
exec > >(tee -a script.log) 2>&1
Run Code Online (Sandbox Code Playgroud)
注意>
标志之间的空间。在 GNU bash 版本 3.2.25(1)-release (x86_64-redhat-linux-gnu) 上对我有用
我想另一种方法是这样的:
#!/bin/bash
# start grouping at the top
{
# your script goes here
do_something_that_outputs_stuff_to_STDOUT
launch_applications_that_output_to_STDOUT
# and at the bottom, redirect everything from the grouped commands
} 2>&1 | tee script.log
Run Code Online (Sandbox Code Playgroud)