Answers:
sh -x script [arg1 ...]
bash -x script [arg1 ...]
这些使您可以了解正在执行的内容。(另请参见答案底部的“澄清”。)
有时,您需要在脚本中控制调试。在这种情况下,正如Cheeto 提醒我的那样,您可以使用:
set -x
这将打开调试。然后,您可以使用以下方法再次将其关闭:
set +x
(您可以通过分析$-
的当前标志来找到当前的跟踪状态x
。)
而且,shell通常提供选项' -n
'表示'不执行'和' -v
'表示'详细'模式。您可以将它们组合使用,以查看shell是否认为它可以执行脚本-如果某处的引用不平衡,这有时会很有用。
有争议的是-x
Bash 中的' '选项与其他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
选项一起使用是明智且明智的,甚至是必要的。否则,调试时和运行脚本时,您可能会(会?)得到不同的行为。
bash
脚本。并且运行带有bash脚本sh -x
将导致其行为完全不同!请更新您的答案。
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
我使用以下方法调试脚本。
set -e
如果任何外部程序返回非零退出状态,则使脚本立即停止。如果您的脚本尝试处理所有错误情况并且应该在其中捕获失败,则这很有用。
set -x
上面提到过,它肯定是所有调试方法中最有用的。
set -n
如果您要检查脚本中的语法错误,则可能也很有用。
strace
看看发生了什么也很有用。如果您还没有自己编写脚本,则特别有用。
strace -f
如果您还想在脚本启动的进程中发现错误,则需要这样做。(这使它变得更加冗长很多倍,但如果将其限制为您感兴趣的syscall仍然有用)。
set -e
是... 有争议的。
这个答案是有效和有用的:https : //stackoverflow.com/a/951352
但是,我发现“标准”脚本调试方法效率低下,不直观且难以使用。对于那些习惯于复杂的GUI调试器的人来说,一切都唾手可得,并且容易完成一些容易遇到的问题(对于棘手的问题则可能如此),这些解决方案并不十分令人满意。
我要做的是结合使用DDD和bashdb。前者执行后者,而后者执行您的脚本。这提供了一个多窗口UI,能够在上下文中单步执行代码并查看变量,堆栈等,而无需花费很多心思来维护上下文或重新列出源代码。
这里有有关设置的指南:http : //ubuntuforums.org/showthread.php?t=660223
我找到了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
现在找到!
这只是一个小例子。
将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上编写了包含许多屏幕截图的教程
我建立了一个Bash调试器。试一试。我希望它将对https://sourceforge.net/projects/bashdebugingbash有帮助
我认为您可以尝试以下Bash调试器:http : //bashdb.sourceforge.net/。
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
)
通过shell的全局变量记录shell脚本的细节很多。我们可以在外壳程序脚本中模拟类似的日志记录:http : //www.cubicrace.com/2016/03/log-tracing-mechnism-for-shell-scripts.html
该帖子详细介绍了诸如INFO,DEBUG,ERROR等日志级别。跟踪详细信息,例如脚本入口,脚本出口,函数入口,函数出口。
样本日志: