我正在将脚本从 bash 转换为 zsh,并且已经在输出中苦苦挣扎了好几天。我希望 stdout 和 stderr 都转到控制台和日志文件。我已经尝试了网上能找到的所有方法,但没有任何乐趣。我已经阅读了 zsh 手册的重定向部分,但没有发现任何帮助,尽管我必须承认我不清楚。
以下是我在脚本开头附近尝试过的实验及其结果:
exec 2>&1 | tee -i test.log # everything in console, log created but empty
exec 2>&1 | tee -i > test.log # everything in console, log created but empty
exec 1>>$LOG; exec 2>&1 # everything in log, none in console
exec 2>&1; exec 1>>$LOG # console gets errors only; log stdout only
exec &> >(tee "$LOG") # works in bash, error in zsh
exec > >(tee -i ${LOG?}) 2>&1 # error
exec |& tee $LOG # error
exec > >(tee $LOG) 2>&1 # error
我还尝试了解 zsh 选项 multios,但无法理解它。它应该默认打开,但当我运行时,我在选项列表中找不到它setopt
。当我跑步时也没有setopt multios
。当我运行时unsetopt multios
,我看到了该选项nomultios
,但这似乎没有帮助
我知道已经有人提出并回答了类似的问题,但答案大多在上面的列表中,对我不起作用。
我认为这不相关,但我还设置了一个获取文件描述符 3 的调试日志。它仅适用于以 >&3 结尾的调试输出行。
任何寻找此类解决方案的人请注意:上述 exec 试验是用混乱的 shebang 完成的,并且纠正后的结果有点不同。除了下面 Gairfowl 的解决方案之外,这也有效:
exec > >(tee $LOG) 2>&1
这似乎有效:
测试:
如果您想每次都覆盖文件而不是追加到文件中,请更改
>>log.txt
为。当变量设置为文件名时>log.txt
,这也适用。这个答案中描述了语法,这里还有更多信息。>>$log
log
multios
这确实需要
multios
启用 - 正如您所指出的,这是默认设置。set -o
(nb: set, not setopt) 可用于显示所有选项的状态;setopt
不带参数仅列出已从默认值更改的选项。关于这些作品的一些注释:
exec ...
-exec
内置程序将用新进程替换当前 shell。当像这样在没有命令参数的情况下调用它时,替换是 的另一个实例zsh
,并将重定向设置为命令行中的新值。效果几乎与在命令行上调用带有这些重定向的命令相同,例如{print abc;print -u2 def} >&1 >log.txt 2>&1
。>&1
- 重定向stdout
到stdout
. 是的,这有点多余 - 这是一个信号,除了以下重定向之外,multios
我们还希望继续发送到其当前目的地(可能是终端)。stdout
>>log.txt
stdout
- 在附加模式下添加对文件的重定向log.txt
。这是一种multios
特定的行为;现在标准输出被发送到两个地方,通过一个zsh
看起来很像的机制tee
。2>&1
- 发送stderr
到与 相同的地方stdout
。由于前面的两个重定向,stdout
将转到两个地方,因此这也会将stderr
输出发送到文件和(可能)终端。print -u<n>
- 仅用于测试。该-u
选项将输出发送到文件描述符<n>
。