bash: 设置 -x 日志到文件

red*_*ven 24 command-line bash scripts debug

我有一个 shell 脚本,set -x可以提供详细/调试输出:

#!/bin/bash

set -x
command1
command2
...
Run Code Online (Sandbox Code Playgroud)

输出如下所示:

+ command1
whatever output from command1
+ command2
whatever output from command2
Run Code Online (Sandbox Code Playgroud)

我的问题是,外壳输出(由set -x)前往stderr,用命令的输出(混合command1command2...)。我很高兴在屏幕上有“正常”输出(比如没有 运行的脚本set -x)和 bash 的“额外”输出分别在一个文件中。

所以我想在屏幕上显示这个:

whatever output from command1
whatever output from command2
Run Code Online (Sandbox Code Playgroud)

这在一个日志文件中:

+ command1
+ command2
Run Code Online (Sandbox Code Playgroud)

(如果日志文件包含所有内容也很好)

set -x 2> file明明好好尝试采取正确的效果,因为它不是set命令的输出,但它改变的bash的行为。

使用bash 2> file整个剧本还没有做正确的事,因为它重定向在这个shell中运行,以及每个命令的标准错误,所以我没有看到的命令的错误消息。

ste*_*ver 28

基于此 ServerFault 答案Send bash -x output to logfile without interupting standard output,现代版本的 bash 包括一个BASH_XTRACEFD专门用于为输出指定备用文件描述符的set -x

所以例如你可以做

#!/bin/bash

exec 19>logfile
BASH_XTRACEFD=19

set -x
command1
command2
...
Run Code Online (Sandbox Code Playgroud)

将输出发送set -x到文件,logfile同时保留以下命令的常规标准输出和标准错误流。

请注意 fd 19 的使用是任意的——它只需要是一个可用的描述符(即不是 0、1、2 或您已经分配的其他数字)。


ter*_*don 6

Steeldriver为您提供了一种方法。或者,您可以简单地将 STDERR 重定向到一个文件:

script.sh 2> logfile
Run Code Online (Sandbox Code Playgroud)

但是,这意味着set -x选项创建的输出和产生的任何其他错误消息都将转到该文件。Steeldriver 的解决方案只会重定向set -x可能是您想要的输出。


red*_*ven 6

一年多后,我找到了正确的解决方案,既可以在屏幕上显示“正常”输出(stdout + stderr - bash trace),又可以在文件 (bash.log) 中同时显示所有输出 (stdout + stderr + bash trace) :

exec   > >(tee -ia bash.log)
exec  2> >(tee -ia bash.log >& 2)
exec 19> bash.log

export BASH_XTRACEFD="19"
set -x

command1
command2
Run Code Online (Sandbox Code Playgroud)


Dra*_*kes 5

自动文件描述符

只是为了稍微改进已接受的答案,并且我将保持其完整,在这里您可以使用 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
Run Code Online (Sandbox Code Playgroud)