如何调试bash脚本?[关闭]


159

有什么方法可以调试bash脚本?例如,打印诸如“呼叫行1”,“呼叫行2”之类的执行日志的内容。


2
还有一个类似的问题在这里:serverfault.com/questions/16204/...
暂停,直至另行通知。

Answers:


195
sh -x script [arg1 ...]
bash -x script [arg1 ...]

这些使您可以了解正在执行的内容。(另请参见答案底部的“澄清”。)

有时,您需要在脚本中控制调试。在这种情况下,正如Cheeto 提醒我的那样,您可以使用:

set -x

这将打开调试。然后,您可以使用以下方法再次将其关闭:

set +x

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

而且,shell通常提供选项' -n'表示'不执行'和' -v'表示'详细'模式。您可以将它们组合使用,以查看shell是否认为它可以执行脚本-如果某处的引用不平衡,这有时会很有用。


有争议的是-xBash 中的' '选项与其他shell不同(请参见注释)。该猛砸手册说:

  • -X

    在扩展它们之后,在执行之前,打印一些简单命令,for命令,case命令,select命令和算术for命令及其参数或关联的单词列表的痕迹。PS4变量的值被扩展,结果值在命令及其扩展的参数之前被打印。

这么多似乎根本没有表明不同的行为。我-x在手册中看不到其他与“ ” 相关的参考。它没有描述启动顺序中的差异。

说明:在诸如Linux之类的典型Linux机器上,“ /bin/sh”是到“ /bin/bash” 的符号链接(或在任何找到Bash可执行文件的地方),两条命令行在运行执行跟踪时达到了等效的效果。在其他系统(例如Solaris和Linux的一些更现代的变体)上,/bin/sh它不是Bash,这两个命令行会(略有不同)产生不同的结果。最值得注意的是,“ /bin/sh”会被Bash中根本无法识别的构造所混淆。(在Solaris上/bin/sh是Bourne外壳;在现代Linux上,有时是Dash -一种较小的,更严格的POSIX专用外壳。)当按这样的名称调用时,“ shebang”行(“ #!/bin/bash'vs '#!/bin/sh'

Bash手册中有关于Bash POSIX模式的部分,与该答案的长期存在但错误的版本相反(另请参见下面的注释),确实详细描述了“以Bash调用为sh”和“以Bash调用为bash'。

在调试(Bash)shell脚本时,将shebang行中命名的shell与该-x选项一起使用是明智且明智的,甚至是必要的。否则,调试时和运行脚本时,您可能会(会?)得到不同的行为。


1
他确实指定了一个bash脚本。并且运行带有bash脚本sh -x将导致其行为完全不同!请更新您的答案。
lhunath

1
@lhunath:“ sh -x”(或“ bash -x”)以什么方式使脚本的行为完全不同?显然,它将跟踪信息输出到stderr。这是给定的(尽管我的回答中未提及)。但是还有什么呢?我在Linux和MacOS X上将“ bash”用作“ sh”,但没有注意到严重的问题。
乔纳森·勒夫勒

6
在启动和运行时都有区别。它们在Bash发行版中有完整记录。
TheBonsai

4
这是bash文档的链接:gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files '如果使用名称sh调用Bash,它将尝试模仿sh的历史版本的启动行为尽可能接近,同时也符合posix标准”
thethinman 2010年

6
并使用PS4提示提供更多有用的信息,例如:export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani 2012年

28

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

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

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

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

strace看看发生了什么也很有用。如果您还没有自己编写脚本,则特别有用。


1
跟踪脚本(即跟踪执行脚本的shell)是一种奇怪的shell调试方法(但可能只适用于少数问题)。
TheBonsai

1
我承认这很奇怪,也很冗长,但是如果将strace的输出限制为几个syscalls,它将变得很有用。

1
请注意,strace -f如果您还想在脚本启动的进程中发现错误,则需要这样做。(这使它变得更加冗长很多倍,但如果将其限制为您感兴趣的syscall仍然有用)。
Random832

set -e是... 有争议的
Charles Duffy

12

这个答案是有效和有用的:https : //stackoverflow.com/a/951352

但是,我发现“标准”脚本调试方法效率低下,不直观且难以使用。对于那些习惯于复杂的GUI调试器的人来说,一切都唾手可得,并且容易完成一些容易遇到的问题(对于棘手的问题则可能如此),这些解决方案并不十分令人满意。

我要做的是结合使用DDD和bashdb。前者执行后者,而后者执行您的脚本。这提供了一个多窗口UI,能够在上下文中单步执行代码并查看变量,堆栈等,而无需花费很多心思来维护上下文或重新列出源代码。

这里有有关设置的指南:http : //ubuntuforums.org/showthread.php?t=660223


刚刚发现ddd,感谢您的回答。在Ubuntu 12.04.3(64位)中,apt-sources版本不起作用。我必须从源代码进行编译和安装,才能开始调试bash脚本。此处的说明-askubuntu.com/questions/156906/…有所帮助。
chronodekar

是的,这是一个问题。我用脚本脚本解决了一段时间-'dddbash'安装/构建DDD,如果错误,则删除旧版本,安装bashdb,等等。(答案已经编辑了此信息)
Stabledog 2014年


10

我找到了shellcheck实用程序,可能有些人觉得它很有趣 https://github.com/koalaman/shellcheck

一个小例子:

$ 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

现在找到!

这只是一个小例子。



幸运的是,该工具已经发展到可以发现剩余错误的地步。
人间


3

将eclipse与带壳&basheclipse的插件一起使用。

https://sourceforge.net/projects/shelled/?source=directory https://sourceforge.net/projects/basheclipse/?source=directory

对于带壳的:下载zip并通过帮助->安装新软件将其导入eclipse:本地归档文件对于basheclipse:将jars复制到eclipse的dropins目录中

遵循提供的步骤https://sourceforge.net/projects/basheclipse/files/?source=navbar

在此处输入图片说明

我在http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html上编写了包含许多屏幕截图的教程


2
这是边界链接的答案(另请参见此处)。您应该扩展答案以在此处包含尽可能多的信息,至少是实际完成建议所需要的最低信息,并且仅将链接用作参考。基本上,Stack Overflow(以及所有Stack Exchange)上的帖子必须是独立的。这意味着您的答案中需要包含足够的信息,以使读者无需走到现场寻找指导。目前,答案并非如此。
Makyen

这是我在看了许多书后发现的第一个答案,这些书实际上表明可以进行真正的调试。标准答案“ set + x”完全匹配自包含的答案,但几乎会故意忽略有关真正调试的真正问题。我赞赏这个答案👏
simbo1905

2

我建立了一个Bash调试器。试一试。我希望它将对https://sourceforge.net/projects/bashdebugingbash有帮助


目前,BDB支持英语和西班牙语。要更改语言,请编辑文件/ etc / default / bdb
abadjm 2014年

屏幕快照看起来很有趣,但是我无法使其运行“ bdb.sh:第32行:bdbSTR [1]:未绑定变量”;顺便说一句,它会在我们对代码执行的每个步骤中显示所有设置变量的当前值吗?
Aquarius Power

2

设置+ x = @ECHO OFF,设置-x = @ECHO ON。


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

#!/bin/bash -xv  

-x:在执行命令时显示命令及其参数。
-v:显示读取时的外壳输入行。


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

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

资源



1

调试技巧 脚本:

使用 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

转储变量或即时跟踪

为了测试一些变量,我有时会这样:

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

用于添加:

declare >&2 -p var1 var2

在第18行并运行生成的脚本(使用args),而无需对其进行编辑。

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

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

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

小样本:

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脚本的答案


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.