有没有办法将使用 -x 选项运行 bash 脚本所显示的信息发送到文件,同时不改变运行该脚本的用户看到的标准输出?
这是我想在我们使用的经常更改的 bash 脚本中实现的调试功能。
答案1
-x 的输出将发送到 stderr,而不是 stdout。但即便如此,这也可能会成为一个问题 —— 很多脚本将对 stderr 的内容具有功能依赖性,在某些情况下,将调试和 stderr 流混合在一起会有点混乱。
Bash 4.1 以上版本确实提供了不同的解决方案:BASH_XTRACEFD 环境变量允许您指定将用于发送调试流的文件描述符。这可以是文件或管道或您喜欢的任何其他 unix-y 优点。
# Use FD 19 to capture the debug stream caused by "set -x":
exec 19>/tmp/my-script.log
# Tell bash about it (there's nothing special about 19, its arbitrary)
export BASH_XTRACEFD=19
# turn on the debug stream:
set -x
# run some commands:
cd /etc
find
echo "Well, that was fun."
# Close the output:
set +x
exec 19>&-
# See what we got:
cat /tmp/my-script.log
再多花点功夫,你就可以做其他事情——比如在 stdout 和/或 stdin 流上执行“tee”,并将它们与调试输出交错,这样你的日志就会更完整。有关这方面的更多详细信息,请参阅https://stackoverflow.com/questions/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself。
与其他方法相比,这种方法的最大优势在于,您不会冒险通过将调试输出注入 stdout 或 stderr 来改变脚本的行为。
答案2
set -x
不会向标准输出发送任何内容,因此不存在任何问题。做执行的操作是写入标准错误,默认情况下写入控制台。
您要做的是将 stdout 重定向到另一个文件,如下所示:
/bin/sh -x /my/script/file 2>/my/log/file
答案3
看man tee
。
您像这样运行它tee commandname filename
,它将显示命令输出stdout
并将其写入filename
。
答案4
tee
命令已经提到过了,但我使用另一种方法来合并跟踪日志中的所有输出。在我看来,这简化了调试。
技巧是使用/dev/tty
命令tee
,因为您无法再重用 stdout/stderr 文件句柄,因为它们已被重定向到您的跟踪日志。
尝试这个:
exec 3>trace.log 2> >(tee -ia /dev/tty >&3) 1> >(tee -ia /dev/tty >&3)
BASH_XTRACEFD=3
set -x
tail -f trace.log
注意:你可以与另一个学期同步阅读。
(GNU bash,版本 5.1.16(1)-release(x86_64-pc-linux-gnu))