8

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

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->
4

5 回答 5

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() {在 AIX ksh88 中时,set -x似乎不会延续到函数本地范围。在同一个 AIX 机器上切换到 ksh93,使用新function a {语法声明的函数也不会将外部set -x作用域带入内部作用域。但是,ksh93 的行为类似于 POSIX sh(以及其他平台上的 ksh88)过去的行为,当函数在旧方法set -x中定义时传递到函数。a(){这可能是由于 ksh93 中的向后兼容性,当函数以旧方式定义时,它会尝试模拟旧行为。

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

于 2010-02-16T17:05:48.243 回答
4

将其添加到您的 shebang 行:

#!/bin/ksh -x

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

#!/bin/ksh
set -x

或者从命令行启动你的脚本:

ksh -x script_name
于 2010-02-16T14:31:12.833 回答
4

set -x使用 ksh88(在 Solaris 10 上)和 ksh93(Fedora 17)测试了一个全局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 更便携。

于 2013-04-14T20:17:24.420 回答
1

请注意,两种类型的函数声明之间的作用域会受到影响

a() {
}

对比

function a {
}

特别是,在前一种情况下,ksh 下的 typset 无法正常工作。在尝试使用递归函数调试脚本时发现。更多在这里:

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

于 2011-08-05T00:41:06.357 回答
1

“set -x”的行为是 AIX shell 的“特殊性”(更不用说 Brain d...)。

您要求“一种设置调试模式的方法......全局”。这是我为实现这一目标所做的工作:

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;有点难看,但它适用于所有 shell,而且收益通常超过成本。

AIX shell“特殊性”的另一个示例:

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

上面应该打印“被困在文件范围内”,但什么也不打印。

于 2012-02-03T16:17:02.140 回答