KSH中变量的作用域

12
我编写了一个示例KornShell函数,用于拆分字符串、将其放入数组中,然后打印出其值。代码如下:
#!/usr/bin/ksh

splitString() {

    string="abc@hotmail.com;xyz@gmail.com;uvw@yahoo.com"

    oIFS="$IFS"; 
    IFS=';' 
    set -A str $string
    IFS="$oIFS"
}

splitString
echo "strings count = ${#str[@]}"
echo "first : ${str[0]}";
echo "second: ${str[1]}";
echo "third : ${str[2]}";

现在echo不会输出数组的值,所以我认为它与定义的数组作用域有关。

我是 Shell 脚本的新手,有谁能帮我理解上面示例中变量的作用域?


太好了!!!脚本现在能正常工作,没有问题。只是我在调用函数时犯了一个小错误。 不过,我仍然想了解KSH中变量的作用域。 - Vivek
2个回答

17

变量的默认作用域是整个脚本。

然而,当你在函数内部声明一个变量时,该变量成为声明它的函数的局部变量。Ksh具有动态作用域的特性,因此该变量也可以在被声明变量的函数所调用的其他函数中访问。这在手册中的函数部分中有简要的说明。请注意,在AT&T ksh(与pdksh及其派生版本以及bash和zsh的类似功能相对)中,这仅适用于使用function关键字定义的函数,而不适用于使用传统的f () { … }语法定义的函数。在AT&T ksh93中,使用传统语法定义的函数中声明的所有变量都是全局的。

主要声明变量的方式是使用typeset builtin。它总是将变量设为局部变量(在AT&T ksh中,只在使用function声明的函数中)。如果你在没有使用typeset声明的情况下给变量赋值,那么它就是全局变量。
ksh文档没有明确说明set -A是将变量设为局部还是全局,不同版本的处理方式也不同。在ksh 93u、pdksh或mksh中,该变量是全局的,你的脚本会打印出其值。你似乎使用的是ksh88或更早版本的ksh,其中作用域是局部的。我认为在函数外初始化str会创建一个全局变量,但我不确定。
请注意,您应该使用一个局部变量来覆盖IFS的值:保存到另一个变量不仅笨拙,而且也很脆弱,因为如果IFS未设置,则无法正确恢复。此外,您应该关闭通配符扩展功能,因为如果字符串包含shell通配符字符?*\[并且其中一个单词恰好与系统上的一个或多个文件匹配,它将被扩展,例如set -A $string,其中stringa;*,将导致str包含当前目录中文件名的列表。
set -A str
function splitString {
  typeset IFS=';' globbing=1
  case $- in *f*) globbing=;; esac
  set -f
  set -A str $string
  if [ -n "$globbing" ]; then set +f; fi
}
splitString "$string"

你正在使用POSIX函数语法。在ksh93中,如果你使用function splitSpring { ... },那么使用typeset进行作用域限定是有效的,否则typeset将被忽略。 - cdarke
@cdarke 没错,谢谢您。请问您了解ksh88的情况吗?我无法在ksh93中重现提问者描述的行为。 - Gilles 'SO- stop being evil'
在ksh88(和bash)中,作用域对于两种风格的函数声明都是相同的。在ksh93中,POSIX函数语法具有POSIX功能,除此之外没有其他影响,因此函数跟踪也会受到影响。 - cdarke
@Gilles 感谢您的详细解释,对我很有帮助 :) - Vivek
1
ksh93仅具有词法作用域,而没有动态作用域。基本上所有与ksh相关的其他shell都使用动态作用域,包括ksh88、bash和zsh。在ksh93中,操作非局部变量需要使用全局变量或通过namerefs传递变量。还有静态局部变量。您还可以使用POSIX函数定义语法修改函数行为,或将函数作为参数调用“点”内置函数。 - ormaaj

3

通常,变量定义后从定义时开始就在所在的shell中全局有效。

typeset命令可以将它们限定为只在定义它们的函数中有效,或者自动导出(即使在更新时也是如此)。

请在man手册或者Korn的书中查看"typeset"和"integer"相关内容。


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