bash 和 ksh 中的间接引用

问题描述 投票:0回答:3

我在 bash 和 ksh 中都遇到间接问题。下面的示例适用于 ksh。它使用 nameref (typeset -n),但它没有按我的预期工作。 func_a 将数组的名称传递给 func_b,以便可以对其进行修改(在这个简单的情况下,func_b 向数组添加了第二个条目)。这显然不起作用,因为 func_b 中定义的第二个局部变量发生了 与 nameref var2 引用的名称相同(来自 func_a 的数组 var1)。 但是拥有本机 nameref 类型(与 bash 中使用的各种 eval hack 相对)的原因之一不应该是不必处理函数(在本例中为 func_b )工作的这些动态范围问题正如某些来电者的预期 函数而不是其他函数仅仅因为本地定义的变量的名称? 看起来 nameref var 基本上只是一个别名或宏,而不是连接两个严格分离的范围的安全方法。我对 bash 也有同样的问题,我希望 ksh 能够像 C 中那样实现间接引用(当然,出于安全原因,不像低级指针,但至少可以说具有类似的“范围隔离”)。我错过了什么吗?

func_b ()
{
  typeset -n var2=$1
  typeset -i var1

  var2[1]=b
}


func_a ()
{
 typeset -a var1=( a )
 func_b var1
 echo "${var1[@]}"
}
bash scope pass-by-reference ksh
3个回答
1
投票

我发现用语法声明函数:

function func_a

它有效。这是因为此 ksh93 语法使排版声明的变量成为本地变量,而使用原始语法 POSIX 规则,并且变量是全局的。

皮特


0
投票

我找到了一个解决方案,这个人做到了http://fvue.nl/wiki/Bash:_Passing_variables_by_reference 完全归功于他。我不喜欢他使用关于 bash 未设置的发现的方式 但任何人都可以按照自己的方式使用这个财产。所以这就是它的要点:

上面的代码在 bash 中会是这样的

func_b ()
{
  local var2=$1
  local -i var1
#do some work to compute the value b
#....
#....
#And in the end assign it with the indirect reference
  eval "$var2[1]=b"
}


func_a ()
{
 local -a var1=( a )
 func_b var1
 echo "${var1[@]}"
}

(可以避免使用 eval,但让我们继续关注重点) 问题显然是 func_b 中的本地 var1 遮蔽了 func_a 中的 var1 由 func_b 中的 var2 引用。所以 func_b 确实按预期运行,即第二个条目 仅当调用者不添加时,调用者的数组中才会通过间接引用添加 将其数组命名为“var1”。假设在“做一些工作”部分之后我知道我已经完成了 与我在 func_b 中使用的局部变量 var1 (可能用于计算想要的 值 b).此时我可以这样做

func_b ()
{
  local var2=$1
  local -i var1
#do some work to compute the value b
#....
#....
#And in the end assign it with the indirect reference
  unset var1 
  eval "$var2[1]=b"
}

去除func_a的var1上的“阴影”并正确终止计算。 但 bash unset 不允许这样做。一旦我在 func_b 中设置了 loval var1 即使 在某些时候我取消设置它,它仍然会隐藏 func_a 的 var1。 上面的人发现 unset 实际上可以通过调用堆栈到达 并取消设置 func_b 的 var1,但仅当从 func_b 调用之上的函数 f 调用调用时 在堆栈中 IF 函数 f 没有在本地定义它自己的 var1 。 基本上如果你这样做

func_the_unshadower ()
{
  unset -v var1
}

func_b ()
{
  local var2=$1
  local -i var1
#do some work to compute the value b
#....
#....
#And in the end assign it with the indirect reference
  func_the_unshadower
  eval "$var2[1]=b"
}

func_a ()
{
 local -a var1=( a )
 func_b var1
 echo "${var1[@]}"
}

它有效.... 显然这只是一个玩具示例,每个人都可以找出自己的首选 使用 unset 这个属性的方法。一个简单的方法是在运行时检查变量是否引用 通过调用不带参数的“local”(其中 返回局部变量列表)。 但最棒的是这不是 bash 中的错误。在上面的链接中有 甚至是 bash 邮件列表中某个线程的链接,其中主要 bash 开发人员 说这是未设置的行为方式,并且它将保持这种方式。


0
投票

我没有 ksh,你没有告诉我们你遇到了什么问题或如何重现它,所以我无法直接解决问题,但我认为你在 bash 中尝试做的事情是:

$ cat tst.sh
#!/usr/bin/env bash

func_b ()
{
    local -n var2=$1
    local var1

    var2[1]=b
}


func_a ()
{
    #local var1
    var1=( a )
    func_b var1
    echo "${var1[@]}"
}

func_a

$ ./tst.sh
a

这有什么问题吗?

© www.soinside.com 2019 - 2024. All rights reserved.