如何调试bash脚本?

cor*_*vus 155 bash shell

有没有办法调试bash脚本?例如,打印一种执行日志的东西,如"呼叫线路1","呼叫线路2"等.

Jon*_*ler 187

sh -x script [arg1 ...]
bash -x script [arg1 ...]
Run Code Online (Sandbox Code Playgroud)

这些可以让您了解正在执行的内容.(另请参阅答案底部附近的"澄清".)

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

set -x
Run Code Online (Sandbox Code Playgroud)

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

set +x
Run Code Online (Sandbox Code Playgroud)

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

此外,shell通常-n为'无执行'和' -v'为'详细'模式提供选项' ; 您可以结合使用这些来查看shell是否认为它可以执行您的脚本 - 如果您在某处有不平衡的引用,偶尔会有用.


有人认为-xBash 中的' '选项与其他shell不同(参见注释).该猛砸手册说:

  • -X

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

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

澄清:在系统,如一个典型的Linux盒,其中" /bin/sh"是一个符号链接" /bin/bash"(或其它地方的击可执行被发现),则两行命令实现运行与执行跟踪脚本的等效效果.在其他系统上(例如,Solaris,以及一些更现代的Linux变体),/bin/sh不是Bash,而且两个命令行会给出(稍微)不同的结果.最值得注意的是,' /bin/sh'会被Bash中的构造混淆,它根本不会识别.(在Solaris上,/bin/sh是Bourne shell;在现代的Linux,它有时是短跑-更小的,更严格的POSIX只壳)当这样的名字调用时,"家当"线(" #!/bin/bash'VS '#!/bin/sh’)在开始该文件的内容对内容的解释方式没有影响.

Bash的手册有一个部分猛砸POSIX模式其中,与此相反的答案的一个长期存在的,但错误的版本(见下面的评论),它描述了广泛的细节之间的差异"猛砸援引为sh援引为"和"击bash".

在调试(Bash)shell脚本时,使用带有-x选项的shebang行中命名的shell将是明智且理智的 - 甚至是必要的.否则,在运行脚本时进行调试时,您可能(将?)获得不同的行为.

  • 在启动和运行时都存在差异.它们在Bash发行版中有完整的记录. (6认同)
  • 并使用PS4提示提供更多有用的信息,例如:`export PS4 ='+($ {BASH_SOURCE}:$ {LINENO}):$ {FUNCNAME [0]:+ $ {FUNCNAME [0]}():}' ` (6认同)
  • 这是bash doc的链接:http://www.gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files'如果用名称sh调用Bash,它会尝试模仿启动行为sh的历史版本尽可能接近,同时符合posix标准 (4认同)

小智 27

我已经使用以下方法来调试我的脚本.

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

set -x 如上所述,它肯定是所有调试方法中最有用的.

set -n 如果要检查脚本是否存在语法错误,则可能也很有用.

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


小智 12

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

但是,我发现"标准"脚本调试方法效率低,不直观且难以使用.对于那些习惯于复杂的GUI调试器的人来说,这些调试器可以轻松解决所有问题(并且可能存在难题),这些解决方案并不十分令人满意.

我所做的是使用DDD和bashdb的组合.前者执行后者,后者执行脚本.这提供了一个多窗口UI,能够在上下文中逐步执行代码并查看变量,堆栈等,而无需不断的心理努力来维护头脑中的上下文或继续重新列出源代码.

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


小智 10

您还可以在脚本中编写"set -x".

  • 你可以写'set + x'来关闭它. (4认同)

Equ*_*ver 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.
Run Code Online (Sandbox Code Playgroud)

修复bug,先试试......

$ 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.
Run Code Online (Sandbox Code Playgroud)

让我们再试一次...

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

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

$ shellcheck test.sh
Run Code Online (Sandbox Code Playgroud)

现在找到!

这只是一个小例子.