如何调试正在运行的Bash脚本

3

我有一个在Ubuntu上运行的bash脚本。

现在是否有可能在不重新启动脚本的情况下查看当前执行的行/命令?

问题在于脚本有时永远不会退出。这真的很难复制(现在我抓住了它),所以我不能停止脚本并开始调试。

任何帮助都将不胜感激。

P.S. 脚本逻辑很难理解,所以我无法通过思考弄清楚为什么它被冻结了。


2
调试shell脚本的常规方法是在开头添加set -x, 但这需要重新启动它。我唯一能想到的建议是使用strace,但我不知道将其输出转换为脚本行有多容易。 - Barmar
2
@FranzHolzinger 他如果不重启脚本,该怎么做呢? - Barmar
重点注意 - “无需重新启动脚本” - long
你可以尝试拦截要去/dev/null的内容,全局替换/dev/null为可写文件(但会得到大量垃圾),或者使用gdb和Bash进程的dup2系统调用将/dev/null的fd更改为另一个文件。这不会精确地告诉你正在处理哪一行,但很有可能命令的大部分输出都被发送到那里,因此它可能会给你一些提示。 - damienfrancois
显示剩余5条评论
1个回答

3

尝试找出 shell 的进程 ID(pid),可以使用 ps -ef | grep <script_name> 命令。 将此 pid 存储到 shell 变量 $PID 中。 通过以下命令查找所有子进程:ps --ppid $PID

ps --ppid $PID

如果您发现一个或多个命令没有响应(例如,它被卡在一系列管道命令中),请尝试多次重复执行该命令。如果命令不改变,则说明脚本卡在某个命令中。此时,您可以将跟踪命令附加到正在运行的子进程:

sudo strace -p $PID

这将展示正在执行的内容,是无限循环(例如从管道读取),还是等待永远不会发生的某些事件。

如果您发现ps --ppid $PID在变化,则表示您的脚本正在前进,但卡在某个地方,例如在脚本中的本地循环。从更改的命令中,可以给您一个提示,在脚本的哪个部分它正在循环。


好的,你的方法至少给了我一些线索。code sudo strace -p $PID code 产生了 code read(3, code 。数字是文件描述符,在使用 lsof 命令后我发现它是 Unix 套接字。因此,脚本调用某些系统操作并等待通过该套接字收到响应。不幸的是,这还不够。 - long
1- 这个脚本卡在哪个命令上了?2- 你能分享一下 cat /proc/${PID}/fdinfo/3 的输出吗? - hesham_EE
很不幸,这个 bug 确实非常罕见...我会在下次出现时尝试运行这个命令。 - long

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接