bash和ksh中的间接引用

bash和ksh中的间接引用,bash,scope,pass-by-reference,ksh,Bash,Scope,Pass By Reference,Ksh,我对bash和ksh中的间接寻址都有问题。以下示例适用于ksh。它使用了nameref(typeset-n),但它并没有像我预期的那样工作。func_a将数组的名称传递给func_b,以便对其进行修改(在本例中,func_b向数组添加第二个条目)。这显然不起作用,因为在func_b中定义的第二个局部变量发生了 与nameref var2引用的数组(func_a中的数组var1)具有相同的名称。 但是使用本机nameref类型(与bash中使用的各种eval hack相反)的原因之一是,如果函数(

我对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变量基本上只是一个别名或宏,而不是连接两个严格分开的作用域的安全方法。我对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的unset的发现的方式 但是任何人都可以用他们自己的方式使用这个属性。以下是它的要点:

上面的代码在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产生阴影 由var2在func_b中引用。因此,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,但仅当从函数f的调用调用到func_b的调用之上时 在堆栈中,如果函数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中的bug。在上面的链接中有 甚至是bash邮件列表中一个线程的链接
表示这是unset的预期行为方式,并将保持这种方式。

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

function func_a
这是有效的。这是因为此ksh93语法使typeset声明的变量为局部变量,而在原始语法中,POSIX规则适用,变量为全局变量


Pete

“看来nameref变量基本上只是一个别名或宏,而不是连接两个严格分开的作用域的安全方式。”但事实上,nameref只是一个字符串。连接两个严格分开的作用域不是一种安全的方法。我猜你缺少的是shell脚本语言的性质。考虑编辑你的问题,包括你的样本输入,需要的输出和当前的输出。很难从文本描述中看出您的期望值,而示例输入和输出很容易理解。祝你好运