set -x
我有一个用于显示详细/调试输出的shell 脚本:
#!/bin/bash
set -x
command1
command2
...
输出如下所示:
+ command1
whatever output from command1
+ command2
whatever output from command2
我的问题是,shell 输出(由 引起set -x
)进入 stderr,与命令的输出(command1
、command2
、...)混合在一起。我很乐意在屏幕上显示“正常”输出(就像脚本在没有 的情况下运行一样set -x
),并在文件中单独显示 bash 的“额外”输出。
所以我想在屏幕上显示这个:
whatever output from command1
whatever output from command2
日志文件中如下内容:
+ command1
+ command2
(如果日志文件包含所有内容也很好)
这set -x 2> file
显然不会产生正确的效果,因为它不是 set 命令的输出,但它改变了 bash 的行为。
对整个脚本使用bash 2> file
也做不到正确,因为它会重定向在此 shell 中运行的每个命令的 stderr,所以我看不到命令的错误消息。
答案1
基于此 ServerFault 答案将 bash -x 输出发送到日志文件而不中断标准输出,现代版本的 bash 包含一个BASH_XTRACEFD
专门用于指定输出的备用文件描述符set -x
例如你可以这样做
#!/bin/bash
exec 19>logfile
BASH_XTRACEFD=19
set -x
command1
command2
...
将输出发送set -x
到文件,logfile
同时为以下命令保留常规标准输出和标准错误流。
请注意,fd 19 的使用是任意的 - 它只需要是一个可用的描述符(即不是 0、1、2 或您已经分配的其他数字)。
答案2
经过一年多的时间,我找到了正确的解决方案,将“正常”输出(stdout + stderr - bash trace)同时显示在屏幕上,并将所有内容(stdout + stderr + bash trace)一起显示在文件(bash.log)中:
exec > >(tee -ia bash.log)
exec 2> >(tee -ia bash.log >& 2)
exec 19> bash.log
export BASH_XTRACEFD="19"
set -x
command1
command2
答案3
钢铁司机给你一种方法。或者,您可以简单地将 STDERR 重定向到文件:
script.sh 2> logfile
但是,这意味着选项产生的输出set -x
和产生的任何其他错误消息都将进入文件。Steeldriver 的解决方案只会重定向输出,set -x
这可能正是您想要的。
答案4
自动文件描述符
只是为了稍微改进一下所接受的答案,并且我会保持它的完整性,在这里您可以使用 Bash 4.1+ 自动文件描述符分配{any_var}
来使用最低可用的文件描述符 - 无需对其进行硬编码。
exec 1> >(tee -ia bash.log)
exec 2> >(tee -ia bash.log >& 2)
# Notice no leading $
exec {FD}> bash.log
# If you want to append instead of wiping previous logs
exec {FD}>> bash.log
export BASH_XTRACEFD="$FD"
set -x
# Just for fun, add this to show the file descriptors in this context
# and see the FD to your bash.log file
filan -s
command1
command2