如何调试 Bash 脚本?

有办法调试 Bash 脚本吗?

例如,打印某种执行日志的东西,比如“调用行1”、“调用行2”等。

174019 次浏览
sh -x script [arg1 ...]
bash -x script [arg1 ...]

这些给你一个正在执行的跟踪。(另见答案底部附近的“澄清”。)

有时,您需要控制脚本中的调试。在这种情况下,作为 奇多 提醒我,你可以使用:

set -x

这将打开调试,然后您可以使用以下命令再次关闭调试:

set +x

(可以通过分析 x的当前标志 $-来查找当前跟踪状态。)

此外,shell 通常提供‘ -n’选项表示‘不执行’,‘ -v’选项表示‘详细’模式; 您可以结合使用这两个选项来查看 shell 是否认为它可以执行您的脚本ーー如果您在某个地方有一个不平衡的引号,那么这两个选项偶尔会很有用。


有争议认为 Bash 中的‘ -x’选项不同于其他 shell (参见注释)。Bash 手册表示:

  • X

    在简单命令、 for命令、 case命令、 select命令和算术 for命令及其参数或相关的单词列表展开之后和执行之前打印它们的跟踪。展开 PS4变量的值,并在命令及其展开的参数之前打印结果值。

这一点似乎根本不能说明行为有什么不同。我没有看到任何其他相关的参考“ -x”在手册。它不描述启动序列中的差异。

澄清 : 在一些系统上,比如一个典型的 Linux 机器,其中‘ /bin/sh’是到‘ /bin/bash’的符号链接(或者找到 Bash 可执行文件的地方) ,这两个命令行实现了相同的效果,即运行脚本时打开执行跟踪。在其他系统上(例如,Solaris 和一些更现代的 Linux 变体) ,/bin/sh不是 Bash,而且这两个命令行给出的结果(略微)不同。最值得注意的是,‘ /bin/sh’会被 Bash 中根本不能识别的构造所混淆。(在 Solaris 上,/bin/sh是 Bourne shell; 在现代 Linux 上,它有时是 Dash ーー更小、更严格的 POSIX shell。)像这样通过名称调用时,文件开头的‘ shebang’行(‘ #!/bin/bash’vs '#!/bin/sh’)对解释内容的方式没有影响。

Bash 手册中有一个关于 Bash POSIX 模式的章节,与这个答案的一个长期但错误的版本相反(参见下面的评论) ,确实详细描述了“ Bash 调用为 sh”和“ Bash 调用为 bash”之间的区别。

在调试(Bash) shell 脚本时,使用 shebang 行中带有 -x选项的 shell 将是明智和理智的,甚至是必要的。否则,你可以(将?)调试时获得与运行脚本时不同的行为。

您还可以在脚本中编写“ set-x”。

我使用了以下方法来调试我的脚本。

如果任何外部程序返回非零退出状态,则 set -e使脚本立即停止。如果您的脚本试图处理所有错误情况,并且应该捕获这样做的失败,那么这将非常有用。

上面提到过 set -x,它肯定是所有调试方法中最有用的。

如果您想检查脚本中的语法错误,set -n也可能很有用。

strace对于查看正在发生的事情也很有用。如果您还没有自己编写脚本,那么它尤其有用。

乔纳森 · 莱弗勒的回答是有效和有用的。

但是,我发现“标准”脚本调试方法效率低下、不直观且难以使用。对于那些习惯于使用复杂的 GUI 调试器的人来说,这些解决方案并不十分令人满意,因为它们可以让你轻松地解决简单的问题(也可能解决困难的问题)。

我确实使用了 DDD和 bashdb 的组合。前者执行后者,后者执行您的脚本。这提供了一个多窗口 UI,可以在上下文中单步执行代码,查看变量、堆栈等,而不需要不断地在脑海中维护上下文或重新列出源代码。

DDD 和 BASHDB < a href = “ http://ubuntuforums.org/showthread.php? t = 660223”rel = “ nofollow noReferrer”> DDD 和 BASHDB 中有关于设置这一点的指导。

我构建了一个 Bash 调试器: Bash 调试 Bash

我发现了 贝壳检查实用程序,也许有些人觉得它很有趣。

举个小例子:

$ cat test.sh
ARRAY=("hello there" world)


for x in $ARRAY; do
echo $x
done


$ shellcheck test.sh


In test.sh line 3:
for x in $ARRAY; do
^-- SC2128: Expanding an array without an index only gives the first element.

修好窃听器,第一次尝试..。

$ cat test.sh
ARRAY=("hello there" world)


for x in ${ARRAY[@]}; do
echo $x
done


$ shellcheck test.sh


In test.sh line 3:
for x in ${ARRAY[@]}; do
^-- SC2068: Double quote array expansions, otherwise they're like $* and break on spaces.

我们再试一次。

$ cat test.sh
ARRAY=("hello there" world)


for x in "${ARRAY[@]}"; do
echo $x
done


$ shellcheck test.sh

找到了!

这只是个小例子。

我想你可以试试这个 Bash 调试器: http://bashdb.sourceforge.net/

通过 shell 的全局变量记录 shell 脚本有大量的细节。我们可以在 shell 脚本中模拟类似的日志记录: 用于 shell 脚本的日志跟踪机制

这篇文章详细介绍了日志级别,比如 INFO、 DEBUG 和 ERROR。跟踪脚本入口、脚本出口、函数入口、函数出口等细节。

日志示例:

Enter image description here

调试 巴斯脚本的一些技巧:

使用 set -[nvx]

除了

set -x

还有

set +x

停止倾倒。

我想谈谈 set -v,它的转储量与欠发达的产量一样小。

bash <<<$'set -x\nfor i in {0..9};do\n\techo $i\n\tdone\nset +x' 2>&1 >/dev/null|wc -l
21


for arg in x v n nx nv nvx;do echo "- opts: $arg"
bash 2> >(wc -l|sed s/^/stderr:/) > >(wc -l|sed s/^/stdout:/) <<eof
set -$arg
for i in {0..9};do
echo $i
done
set +$arg
echo Done.
eof
sleep .02
done
- opts: x
stdout:11
stderr:21
- opts: v
stdout:11
stderr:4
- opts: n
stdout:0
stderr:0
- opts: nx
stdout:0
stderr:0
- opts: nv
stdout:0
stderr:5
- opts: nvx
stdout:0
stderr:5

Dump variables or tracing 临时起意

为了测试一些变量,我有时使用以下方法:

bash <(sed '18ideclare >&2 -p var1 var2' myscript.sh) args

补充说明:

declare >&2 -p var1 var2

并运行结果脚本(使用 Args) ,而不必编辑它们。

当然,这可以用来添加 set [+-][nvx]:

bash <(sed '18s/$/\ndeclare -p v1 v2 >\&2/;22s/^/set -x\n/;26s/^/set +x\n/' myscript) args

它将在第18行之后添加 declare -p v1 v2 >&2,在第22行之前添加 set -x,在第26行之前添加 set +x

一个小例子:

bash <(sed '2,3s/$/\ndeclare -p LINENO i v2 >\&2/;5s/^/set -x\n/;7s/^/set +x\n/' <(
seq -f 'echo $@, $((i=%g))' 1 8)) arg1 arg2
arg1 arg2, 1
arg1 arg2, 2
declare -i LINENO="3"
declare -- i="2"
/dev/fd/63: line 3: declare: v2: not found
arg1 arg2, 3
declare -i LINENO="5"
declare -- i="3"
/dev/fd/63: line 5: declare: v2: not found
arg1 arg2, 4
+ echo arg1 arg2, 5
arg1 arg2, 5
+ echo arg1 arg2, 6
arg1 arg2, 6
+ set +x
arg1 arg2, 7
arg1 arg2, 8

注: 关注 $LINENO。它将受到 在飞机上修改的影响!

(要查看不执行的结果脚本,只需删除 bash <() arg1 arg2)

一步一步,执行时间

看看 我关于如何分析 Bash 脚本的回答

安装 VisualStudio 代码,然后添加 Bash 调试扩展插件,就可以在可视模式下进行调试了。看到它 给你的行动。

Enter image description here

set +x = @ECHO OFF, set -x = @ECHO ON.

您可以将 -xv选项添加到标准 开始吧中,如下所示:

#!/bin/bash -xv

-x: 在执行命令时显示命令及其参数。 -v: 在读取 shell 输入行时显示它们。


ltrace是另一个类似于 Strace的 Linux 实用程序。但是,ltrace列出了在可执行文件或正在运行的进程中调用的所有库调用。它的名称本身来自库调用跟踪。

例如:

ltrace ./executable <parameters>
ltrace -p <PID>

来源

使用带有 Shelled 和 BashEclipse 插件的 Eclipse。

对于 炮弹: 下载 ZIP 文件并通过菜单 救命安装新软件: 本地存档将其导入 Eclipse。对于 BashEclipse: 将 JAR 文件复制到 Eclipse 的 坠子目录中

遵循 < a href = “ https://sourceforge.net/Projects/bashellipse/files/? source = navbar”rel = “ nofollow noReferrer”> BashEclipse files 中提供的步骤

Enter image description here

我在 Bash: 为 Bash 编程启用 Eclipse | Plugin Shelled (shell 编辑器)上写了一个有很多截图的教程