KornShell - 全局设置“-x”(调试)标志?

时间:2010-02-16 14:16:20

标签: shell debugging scripting ksh script-debugging

有没有办法在全局的KornShell(ksh)脚本上设置调试模式(set -x)?目前我似乎做了类似以下的事情:

a(){
   set -x
   #commands
}

b(){
   set -x
   #more commands
}

set-x 
a
#commands
b

我真的只想在一个地方调用set-x命令。

注意:这完全在AIX上的KSH88中。

示例:

#!/bin/ksh
set -x

a(){
   echo "This is A!"
}

b(){
   echo "This is B!"
}

a
echo "Outside"
b
dev2:/home/me-> ./testSetX
+ a
This is A!
+ echo Outside
Outside
+ b
This is B!
dev2:/home/me->

5 个答案:

答案 0 :(得分:8)

这是HP-UX计算机上的ksh88:

me@host ..dev/
$ cat ./test/verbose
#!/bin/ksh
set -x

hello() {
  print $1
}

hello kapow!
exit

me@host..dev/
$ ./test/verbose    
+ hello kapow!
+ print kapow!
kapow!
+ exit

确定看起来就像工作正常一样。我验证它在第一次函数调用之前的任何地方都可以使用“set -x”。

我搬到了AIX系统,遇到了你描述的问题。当函数在AIX ksh88中定义为function a {a() {时,set -x似乎不会继续进入函数局部范围。在同一个AIX框中切换到ksh93,使用新的function a {语法声明的函数也不会将外部set -x带入内部作用域。但是,当旧函数set -x中定义函数时,ksh93的行为类似于POSIX sh(以及其他平台上的ksh88),它将a(){传递给函数。这可能是由于ksh93中的向后兼容性,它在以旧方式定义函数时尝试模拟旧行为。

因此,您可以暂时将解释器切换到ksh93以进行调试,然后如果您不喜欢使用更长的数组,关联数组,浮点数学,命名空间支持和rougly,则切换回ksh88 ksh93带来的执行速度提高了10倍。 ;)因为在AIX上使用ksh88看起来答案是“不,你不能这样做”。 :(

答案 1 :(得分:4)

将它添加到你的shebang系列:

#!/bin/ksh -x

或者将其设置在脚本的顶部:

#!/bin/ksh
set -x

或者从命令行启动脚本:

ksh -x script_name

答案 2 :(得分:4)

我使用ksh88(在Solaris 10上)和ksh93(Fedora 17)测试了全局set -x,并且脚本顶部的全局set -x命令都没有函数本地范围(即它没有任何局部效应)。

作为一种解决方法,您可以为范围内的所有函数启用本地命令跟踪(在定义它们之后)以及通过typeset调用它们之前:

$ cat test.ksh
PS4='$LINENO: '

set -x

function foo {
  print Hello
}

bar() {
  print World
}

typeset -ft `typeset +f` 

foo
bar

ksh88下的输出(Solaris 10):

$ ksh test.ksh 
13: typeset +f
13: typeset -ft bar foo
15: foo
1: print Hello
Hello
16: bar
1: print World
World

排版已注释掉

$ ksh test.ksh 
15: foo
Hello
16: bar
World

ksh93下的输出(Fedora 17):

$ ksh test.ksh
13: typeset +f
13: typeset -ft 'bar()' foo
15: foo
6: print Hello
Hello
16: bar
10: print World
World

排版已注释掉

$ ksh test.ksh
15: foo
Hello
16: bar
10: print World
World

bash下的输出

typeset已注释掉,print已替换为echo:

$ bash test.ksh
15: foo
6: echo Hello
Hello
16: bar
10: echo World
World

(Fedora 17上的bash 4.2.39(1))

Fedora 17上zsh 5.0.2下的相同输出。

结论

使用Ksh时,仅使用ksh93和fnname()函数定义语法,全局set -x也具有本地范围。基于typeset -ft的解决方法是为所有函数启用命令跟踪的一种相对较轻的方法。

在bash(和zsh)中,全局set -x按预期工作,即它还具有所有函数的本地范围。

因此,当使用bash而不是ksh编写新脚本时,可能是更好的选择。

作为旁注:bash可能比ksh88更便携 - 特别是比ksh93更便携。

答案 3 :(得分:1)

请注意,范围界定会影响两种类型的函数声明

a(){ }

VS。

函数a { }

特别是,ksh下的typset不能像前面的情况那样工作。在尝试使用递归函数调试脚本时发现。更多信息:

http://www.dartmouth.edu/~rc/classes/ksh/functions.html

答案 4 :(得分:1)

“set -x”的行为是AIX shell的“特性”(不是说大脑......)。

你问过“一种设置调试模式......全局的方法”。 以下是我要做的事情:

set_x="${set_x-:}"; # Defaults to ":" (NOOP) unless already non-empty
# Using ":" instead of "" makes termination via semicolon work,
# which in turn allows inlining, especially when using SSH.
# Alternatively, if tracing should be on by default:
#set_x="${set_x-set -x}"; # Defaults to "set -x" unless already non-empty

$set_x; # Apply to file scope

f() {
    $set_x; # Apply to local scope
    echo working...;
}
main() {
    $set_x; # Apply to local scope
    f;
    ssh localhost $set_x\; hostname; # Apply to remote shell scope
    ssh localhost "set_x=\"$set_x\" foo"; # Apply to foo called in remote shell
}
main;

要启用跟踪,请在脚本环境中将$set_x设置为“set -x”。 要在逐个呼叫的基础上对此进行控制,请在呼叫前加上“set_x='set -x'”。 因为使用了环境变量,所以此方法自然适用于嵌套调用。

$set_x;”的所有用法都有点难看,但它适用于所有贝壳, 并且收益通常超过成本。

AIX shell“peculiarity”的另一个例子:

set -e;
trap "echo trapped at file scope" EXIT;
f() { return 1; }
main() { f; }
main;

以上内容应打印“陷入文件范围”,但不打印任何内容。