有没有办法在全局的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->
答案 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
$ 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
$ 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
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不能像前面的情况那样工作。在尝试使用递归函数调试脚本时发现。更多信息:
答案 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;
以上内容应打印“陷入文件范围”,但不打印任何内容。