Bash:调试选项和函数

9
如果我运行:
bash -x myscript.sh

我将获得调试输出。

但是,如果在myscript.sh中有一个函数,则该函数中的代码对-x选项免疫。它仅向输出写入函数名称。

如何为bash脚本中的函数获取调试输出?

更新:

根据ztank1013的回答,我刚意识到我使用的是ksh,而不是bash。似乎bash在我的系统中默认启用了functrace选项(感谢bash-o-logist)

我很满意,但为了社区的利益,我将保持这个问题针对ksh开放。

对于脚本:

#!/bin/ksh

a=2
testering(){
        a=3
        if [ $a -eq 3 ]; then
                echo lili
        fi
}
if [ $a -eq 2 ]; then
        echo mimi
fi

testering
exit

ksh -x ./testdebug.sh的输出结果如下:

+ a=2
+ [ 2 -eq 2 ]
+ echo mimi
mimi
+ testering
lili
+ exit

所以,对于ksh,诀窍是什么?
(如果没有答案,那么“正确”的答案将归于bash-o-logist。)
5个回答

13

使用bash,您可以在脚本中使用functrace选项。

set -o functrace

请参阅 bash 的 man 手册以获取其他调试选项。


1
请问您能否详细说明启用functrace的作用是什么? - user674669

4

我无法重现您的问题,实际上,根据我的测试脚本 (debug.sh):

[root ~]# cat debug.sh
#!/bin/bash
fun01 () {
echo "BUT HERE I am inside the function fun01() body"
}
echo "HERE I am outside the function fun01() body!"
sleep 2
fun01
exit

我关闭了调试选项来运行它:

[root ~]# ./debug.sh
HERE I am outside the function fun01() body!
BUT HERE I am inside the function fun01() body

并打开 (bash -x ...):

[root ~]# bash -x ./debug.sh
+ echo 'HERE I am outside the function fun01() body!'
HERE I am outside the function fun01() body!
+ sleep 2
+ fun01
+ echo 'BUT HERE I am inside the function fun01() body'
BUT HERE I am inside the function fun01() body
+ exit

据我所见,fun01()函数内执行的代码行以一个加号+开头,这是调试器在工作。
即使我添加了变量或if/then/else条件结构,我仍然会获得所有调试信息。
[root@ ~]# cat debug-new.sh
#!/bin/bash
fun01 () {
INSIDEVAR='Never really use this one'
echo "BUT HERE I am inside the function fun01() body"
if [ true ] ; then echo 'this is going to be printed always!' ; fi
}
echo "HERE I am outside the function fun01() body!"
sleep 2
fun01
exit

再次执行:

[root@ ~]# bash -x debug-new.sh
+ echo 'HERE I am outside the function fun01() body!'
HERE I am outside the function fun01() body!
+ sleep 2
+ fun01
+ INSIDEVAR='Never really use this one'
+ echo 'BUT HERE I am inside the function fun01() body'
BUT HERE I am inside the function fun01() body
+ '[' true ']'
+ echo 'this is going to be printed always!'
this is going to be printed always!
+ exit

1
你不能仅在函数内部回显一些语句。尝试在函数内部声明变量并使用if/else语句。 - bash-o-logist

2
在ksh中使用typeset -ft 函数名来跟踪函数。

在脚本中,将*function-name*替换为正在调试的函数名。 - yrk

0

这是我在bash脚本中强制打开或关闭函数块内调试的方法。

如果脚本启动时调试已经打开,则在函数块内也会打开。每个函数块都有开始和结束消息,以便更轻松地跟踪。

这是用于运行时调试的。最好将输出重定向到日志文件以供稍后分析,例如:

bash -x ./runtime_bash_debugging>log 2>&1
-- or --
./runtime_bash_debugging>log 2>&1

在开始时开启调试的示例输出

$ bash -x ./runtime_bash_debugging.sh
+ run_me_first
+ FN_NAME=run_me_first
+ MSG='BEGINNING OF: run_me_first'
+ test '' = on
++ date
+ echo 'I run first, it'\''s Sat Oct 27 19:11:06 MDT 2018'
I run first, it's Sat Oct 27 19:11:06 MDT 2018
+ MSG='END OF: run_me_first'
+ test '' = on
+ run_me_second
+ FN_NAME=run_me_second
+ MSG='BEGINNING OF: run_me_second'
+ test '' = on
+ echo 'I run second, my PID is 5744'
I run second, my PID is 5744
+ MSG='END OF: run_me_second'
+ test '' = on
+ echo Goodbye
Goodbye
+ exit

在开始时关闭调试的示例输出

$ ./runtime_bash_debugging.sh
I run first, it's Sat Oct 27 19:11:09 MDT 2018
I run second, the PID is 4784
Goodbye

脚本

#!/bin/bash

# runtime bash debugging

fn_check_xtrace() {
    XTRACE_BEGIN_STATE=`set -o|awk '$1=="xtrace"{print $2}'`
    echo "${XTRACE_BEGIN_STATE}"
}


function run_me_first() {
    FN_NAME="run_me_first"
    MSG="BEGINNING OF: ${FN_NAME}"

    if test "${XTRACE_BEGIN_STATE}" = "on"
    then
    set -x
    fi

    echo "I run first, it's `date`"

    MSG="END OF: ${FN_NAME}"

    if test "${XTRACE_BEGIN_STATE}" = "on"
    then
    set -x
    fi
}


function run_me_second() {
    FN_NAME="run_me_second"
    MSG="BEGINNING OF: ${FN_NAME}"

    if test "${XTRACE_BEGIN_STATE}" = "on"
    then
    set -x
    fi

    echo "I run second, the PID is $$"

    MSG="END OF: ${FN_NAME}"

    if test "${XTRACE_BEGIN_STATE}" = "on"
    then
    set -x
    fi
}

run_me_first

run_me_second

echo "Goodbye"

exit

0

截图看起来很有前途,但是无法运行。1 /usr/share/bdb $ pwd /usr/share/bdb 1 /usr/share/bdb $ ./bdb.sh + for bdbINC in inc/bdb.lang inc/bdb.vars inc/bdb.lib + INCFICH=/usr/share/bdb/inc/bdb.lang + typeset -u INCUPR=inc/bdblang + INCFLAG=INC/BDBLANG_INCLUDE ./bdb.sh: line 29: INC/BDBLANG_INCLUDE: bad substitution + exit我的西班牙语太糟糕了,无法理解你的代码。 - Red Pill

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接