【问题标题】:Scope of variables in KSHKSH 中的变量范围
【发布时间】:2012-08-13 14:47:28
【问题描述】:

我编写了一个示例 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 中变量的范围

标签: shell unix scripting ksh


【解决方案1】:

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

但是,当您在函数内声明变量时,该变量将成为声明它的函数的局部变量。 Ksh 具有dynamic scoping,因此该变量也可以在由声明该变量的函数调用的函数中访问。这在section on functions in the manual 中有简要记录。请注意,在 AT&T ksh(相对于 pdksh 及其衍生产品,以及 bash 和 zsh 的类似功能)中,这只适用于使用 function 关键字定义的函数,而不适用于使用传统 f () { … } 语法定义的函数。在 AT&T ksh93 中,使用传统语法定义的函数中声明的所有变量都是全局变量。

声明变量的主要方式是使用typesetbuiltin。它总是使变量成为本地变量(在 AT&T ksh 中,仅在使用 function 声明的函数中)。如果您在没有使用 typeset 声明的情况下分配给变量,则它是全局变量。

ksh 文档没有指定 set -A 是使变量成为局部变量还是全局变量,并且不同的版本也可以。在 ksh 93u、pdksh 或 mksh 下,该变量是全局变量,您的脚本会打印出该值。您似乎拥有 ksh88 或更旧版本的 ksh,其范围是本地的。我认为在函数外部初始化str 会创建一个全局变量,但我不确定。

请注意,您应该使用局部变量来覆盖IFS 的值:保存到另一个变量不仅笨拙,而且很脆弱,因为如果未设置它就无法正确恢复IFS。此外,您应该关闭 globbing,否则如果字符串包含 shell globbing 字符 ?*\[ 并且其中一个单词恰好匹配您系统上的一个或多个文件,它将被扩展,例如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 进行范围界定可以正常工作,否则将忽略排版以进行范围界定。
  • @cdarke 你说得对,谢谢。你碰巧知道ksh88的情况吗?我无法重现提问者在 ksh93 中描述的行为。
  • 在 ksh88(和 bash)中,作用域对于两种风格的函数声明都是一样的。在 ksh93 中,POSIX 函数语法具有 POSIX 功能,没有其他功能,因此函数跟踪也会受到影响。
  • @Gilles 感谢您的详细解释。它帮助了很多:)
  • ksh93 只有词法作用域,而不是动态的。基本上所有其他与 ksh 相关的 shell 都使用动态范围,包括 ksh88、bash 和 zsh。在 ksh93 中,操作非局部变量需要使用全局变量,或者通过 namerefs 传递变量。还有静态局部变量。您还可以使用 POSIX 函数定义语法修改函数行为,或将函数作为“dot”内置函数的参数调用。
【解决方案2】:

变量通常是全局的,从它们被定义时就被定义在其中。

typeset 命令可以使它们成为定义它们的函数的本地函数,或者使它们自动导出(即使它们已更新)。

在手册页或 Korn 的书中阅读“排版”和“整数”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-10
    • 2021-11-14
    • 2012-03-08
    • 2012-05-03
    相关资源
    最近更新 更多