我有一个包含大量输出的 bash 脚本,我想更改该脚本(而不是创建一个新脚本)以将所有输出复制到一个文件,就像我通过 tee 传输它时发生的情况一样。
我有一个文件脚本:
#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT
launch_applications_that_output_to_STDOUT
fini
我想将 STDOUT 复制到一个文件中脚本日志./script.sh | tee script.log
而不必每次都打字。
谢谢,汤姆
答案1
我无法让 Dennis 的非常简单的一行代码发挥作用,所以这里有一个更复杂的方法。我会先尝试他的方法。
如上所述,您可以使用 exec 重定向整个脚本的标准错误和标准输出。如下所示:
exec > $LOGFILE 2>&1
这会将所有 stderr 和 stdout 输出到 $LOGFILE。
现在,由于您希望将其显示在控制台和日志文件中,因此您还必须使用命名管道,以便 exec 进行写入,以及 tee 进行读取。
(Dennis 的一行代码在技术上也做到了这一点,尽管显然方式不同)管道本身是使用创建的mkfifo $PIPEFILE
。然后执行以下操作。
# 开始将 tee 写入日志文件,但从我们的命名管道中提取其输入。 tee $LOGFILE < $PIPEFILE & # 捕获 tee 的进程 ID 用于等待命令。 TEEPID=$! # 将其余的 stderr 和 stdout 重定向到我们的命名管道。 执行 > $PIPEFILE 2>&1 echo“在此发出你的命令” 回显“所有标准输出都将得到满足。” echo "他们的标准错误也是如此" >&2 # 关闭 stderr 和 stdout 文件描述符。 执行 1>&- 2>&- # 由于管道的另一端已经关闭,因此等待 tee 完成。 等待$TEEPID
如果想要彻底一点,您可以在脚本的开始和结束时创建和销毁命名管道文件。
顺便说一下,这些内容大部分都是我从一位陌生人的博文中收集到的:(存档版本)
答案2
只需将其添加到脚本的开头即可:
exec > >(tee -ia script.log)
这会将发送到 stdout 的所有输出附加到文件script.log
,保留之前的内容。如果您想在每次运行脚本时重新开始,只需在该命令rm script.log
之前添加exec
或者-a
从命令中删除tee
。
该-i
选项导致tee
忽略中断信号并可能允许tee
捕获更完整的输出集。
添加此行以捕获所有错误(在单独的文件中):
exec 2> >(tee -ia scripterr.out)
多个符号之间的空格>
很重要。
答案3
这是 Dennis Williamson 之前发布的答案的合并版本。将 err 和 std 输出以正确的顺序附加到 script.log。
将此行添加到脚本的开头:
exec > >(tee -a script.log) 2>&1
注意符号之间的空格>
。对我而言,适用于 GNU bash,版本 3.2.25(1)-release (x86_64-redhat-linux-gnu)
答案4
如果您想要输出的副本,您可以使用tee
以下方式:
#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT | tee script.log
launch_applications_that_output_to_STDOUT | tee -a script.log
fini
但是,这只会将 stdout 记录到 script.log。如果您想确保 stderr 和 stdout 都重定向,请使用:
#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT 2>&1 | tee script.log
launch_applications_that_output_to_STDOUT 2>&1 | tee -a script.log
fini
你甚至可以用一个小功能让它变得更美观一些:
#!/bin/bash
LOGFILE="script.log"
# Wipe LOGFILE if you don't want to add to it at each run
rm -f "$LOGFILE"
function logcmd() {
local cmd="$1" logfile=${LOGFILE:-script.log} # Use default value if unset earlier
# Launch command, redirect stderr to stdout and append to $logfile
eval '$cmd' 2>&1 | tee -a "$logfile"
}
init
logcmd "do_something_that_outputs_stuff_to_STDOUT"
logcmd "launch_applications_that_output_to_STDOUT"
fini