如何debugging一个bash脚本?

有没有什么办法来debugging一个bash脚本? 例如,打印某种执行日志,如“呼叫线路1”,“呼叫线路2”等

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

这些给你一些正在执行的内容。 (另请参阅答案底部的“澄清”部分。)

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

 set -x 

这将打开debugging。 然后您可以再次closures它:

 set +x 

(你可以通过分析$- (当前的标志,找出当前的跟踪状态)。

另外,shell通常为'不执行'提供选项' -n ','verbose'模式提供' -v '选项; 您可以结合使用这些参数来查看shell是否认为它可以执行您的脚本 – 偶尔有用的,如果您有不平衡的报价。


有争论说,Bash中的' -x '选项与其他shell不同(请参阅注释)。 Bash手册说:

  • -X

    打印一条简单的命令, for命令, case命令, select命令,以及for命令及其参数或关联的单词列表被展开之后以及在执行之前的算术。 PS4variables的值被扩展,结果值被打印在命令及其扩展参数之前。

这似乎并不表示不同的行为。 在手册中我没有看到任何其他相关的“ -x ”的引用。 它没有描述启动顺序的差异。

说明 :在典型的Linux系统上,' /bin/sh '是' /bin/bash '的符号链接(或者Bash可执行文件的位置),这两个命令行实现了运行脚本的等效效果与执行追踪。 在其他系统上(例如Solaris和更现代的Linux版本), /bin/sh不是Bash,两个命令行会给出(稍微)不同的结果。 最值得注意的是,' /bin/sh '会被Bash中的构造所混淆,它根本不能识别。 (在Solaris上, /bin/sh是一个Bourne shell;在现代Linux上,它有时是Dash – 一个更小,更严格的POSIX-only shell)。当被这样的名字调用时,'shebang'行(' #!/bin/bash ' '#!/bin/sh ')对文件内容的解释没有任何影响。

Bash手册有一个关于Bash POSIX模式的部分,与这个答案的一个长期但错误的版本(也见下面的注释)相反,详细地描述了“作为sh调用的bash”和调用的bash之间的区别作为bash '。

在debugging(Bash)shell脚本时,使用-x选项在shebang行中命名的shell将是明智和理智的 – 甚至是必要的。 否则,从运行脚本进行debugging时,您可能会(将?)得到不同的行为。

我用下面的方法来debugging我的脚本。

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

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

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

strace也是有用的,看看发生了什么事情。 如果你没有自己写脚本,特别有用。

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

但是,我发现“标准”脚本debugging方法效率低,不直观,而且很难使用。 对于那些习惯于使用复杂的GUIdebugging器的人来说,这些解决scheme并不令人满意。

我所做的是使用DDD和bashdb的组合。 前者执行后者,后者执行你的脚本。 这提供了一个多窗口的用户界面,能够在上下文中遍历代码并查看variables,堆栈等,而不需要经常的精力来维护头脑中的上下文或者重新列出源代码。

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

你也可以在脚本中写“set -x”。

我发现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 

现在找!

这只是一个小例子。

我build了一个Bashdebugging器。 只要试一试。 我希望它会帮助https://sourceforge.net/projects/bashdebugingbash

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

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


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

 #!/bin/bash -xv 

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


ltrace是另一个类似于strace Linux实用程序。 但是, ltrace列出了在可执行文件或正在运行的进程中调用的所有库调用。 它的名字本身来自图书馆电话追踪。 例如:

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

资源

一些技巧来debuggingbash脚本:

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

转储variables或即时追踪

为了testing一些variables,我使用了这个:

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

添加:

 declare >&2 -p var1 var2 

在第18行并运行结果脚本(带有参数 ),而不必编辑它们。

当然,这可以用于添加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将受到dynamic修改的影响!

(要查看生成的脚本没有执行,只需删除bash <() arg1 arg2

一步一步,执行时间

看看我的关于如何configurationbash脚本的答案

安装VSCode ,然后添加bashdebugging扩展,并准备好在可视模式下进行debugging。 看到这里在行动。

在这里输入图像描述

使用eclipse插件shelled和basheclipse。

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

对于shelled:下载zip并通过帮助将其导入eclipse – >安装新的软件:local archive for basheclipse:将jar复制到eclipse的dropins目录下

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

在这里输入图像描述

我在http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html上写了很多截图的教程;

通过shell的全局变化对shell脚本进行日志logging有很多细节。 我们可以在shell脚本中模拟类似的日志logging: http : //www.cubicrace.com/2016/03/log-tracing-mechnism-for-shell-scripts.html

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

示例日志:

在这里输入图像描述