我怎样用"tee"和管道将stderr写入文件?

2024-05-23 13:27:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我知道如何使用teeaaa.sh的输出(STDOUT)写入bbb.out,同时仍在终端中显示:

./aaa.sh | tee bbb.out

我现在如何将STDERR写入名为ccc.out的文件,同时仍显示该文件?


Tags: 文件终端shstderrstdoutoutbbbccc
3条回答

我想你还是想在终端上看到STDERR和STDOUT。你可以去找乔希·凯利的答案,但我发现在后台保留一个tail,它会输出你的日志文件,非常烦琐。请注意,您需要保存一个exra FD,并通过终止它来进行清理,技术上应该在trap '...' EXIT中这样做。

有更好的方法可以做到这一点,而且您已经发现了:tee

只是,不要只把它用在stdout上,要有一个stdout的tee和一个stderr的tee。你将如何做到这一点?进程替换和文件重定向:

command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)

让我们分开来解释一下:

> >(..)

>(...)(进程替换)创建一个FIFO并让tee监听它。然后,它使用>(文件重定向)将command的STDOUT重定向到第一个tee正在侦听的FIFO。

同样的第二件事:

2> >(tee -a stderr.log >&2)

我们再次使用进程替换来生成tee进程,该进程从STDIN读取并将其转储到stderr.logtee将它的输入输出回STDOUT,但是由于它的输入是我们的STDERR,我们想再次将tee的STDOUT重定向到我们的STDERR。然后我们使用文件重定向将command的STDERR重定向到FIFO的输入(tee的STDIN)。

http://mywiki.wooledge.org/BashGuide/InputAndOutput

进程替换是那些非常可爱的东西之一,你可以选择bash作为外壳,而不是sh(POSIX或Bourne)。


sh中,您必须手动执行以下操作:

out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$"
mkfifo "$out" "$err"
trap 'rm "$out" "$err"' EXIT
tee -a stdout.log < "$out" &
tee -a stderr.log < "$err" >&2 &
command >"$out" 2>"$err"

为什么不干脆:

./aaa.sh 2>&1 | tee -a log

这只会将stderr重定向到stdout,因此tee会同时回显到日志和屏幕。也许我漏掉了一些东西,因为其他的解决方案看起来很复杂。

注意:由于bash版本4,您可以使用|&作为2>&1 |的缩写:

./aaa.sh |& tee -a log

这可能对人们通过谷歌找到这个有用。只需取消注释您想要尝试的示例。当然,可以随意重命名输出文件。

#!/bin/bash

STATUSFILE=x.out
LOGFILE=x.log

### All output to screen
### Do nothing, this is the default


### All Output to one file, nothing to the screen
#exec > ${LOGFILE} 2>&1


### All output to one file and all output to the screen
#exec > >(tee ${LOGFILE}) 2>&1


### All output to one file, STDOUT to the screen
#exec > >(tee -a ${LOGFILE}) 2> >(tee -a ${LOGFILE} >/dev/null)


### All output to one file, STDERR to the screen
### Note you need both of these lines for this to work
#exec 3>&1
#exec > >(tee -a ${LOGFILE} >/dev/null) 2> >(tee -a ${LOGFILE} >&3)


### STDOUT to STATUSFILE, stderr to LOGFILE, nothing to the screen
#exec > ${STATUSFILE} 2>${LOGFILE}


### STDOUT to STATUSFILE, stderr to LOGFILE and all output to the screen
#exec > >(tee ${STATUSFILE}) 2> >(tee ${LOGFILE} >&2)


### STDOUT to STATUSFILE and screen, STDERR to LOGFILE
#exec > >(tee ${STATUSFILE}) 2>${LOGFILE}


### STDOUT to STATUSFILE, STDERR to LOGFILE and screen
#exec > ${STATUSFILE} 2> >(tee ${LOGFILE} >&2)


echo "This is a test"
ls -l sdgshgswogswghthb_this_file_will_not_exist_so_we_get_output_to_stderr_aronkjegralhfaff
ls -l ${0}

相关问题 更多 >