0

我在 bash 和 ksh 中都有间接问题。下面的示例适用于 ksh。它使用了一个 nameref (typeset -n),但它并没有像我预期的那样工作。func_a 将数组的名称传递给 func_b 以便可以对其进行修改(在这个简单的例子中,func_b 将第二个条目添加到数组中)。这显然不起作用,因为 func_b 中定义的第二个本地 var 恰好与 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[@]}"
}
4

2 回答 2

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_b 中的 var2 引用的 func_a 中的 var1。所以 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 调用调用时,如果函数 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 开发人员说这是 unset 的预期行为方式,它将保持这种方式。

于 2013-10-06T06:12:41.247 回答
0

我发现使用以下语法声明函数:

function func_a

它的工作原理。这是因为这种 ksh93 语法使排版声明的变量是局部的,而使用原始语法 POSIX 规则适用并且变量是全局的。

皮特

于 2015-02-17T17:10:11.743 回答