【问题标题】:indirect references in bash and kshbash 和 ksh 中的间接引用
【发布时间】:2013-10-05 21:48:25
【问题描述】:

我在 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[@]}"
}

【问题讨论】:

  • "似乎 nameref var 基本上只是一个别名或宏,而不是连接两个严格分隔的范围的安全方法。"但是,事实上,nameref 只是一个字符串。连接两个严格分开的范围不是一种安全的方法。我猜你缺少的是 shell 脚本语言的本质。
  • 考虑编辑您的问题以包括您的示例输入、所需输出和当前输出。很难从您的文本描述中说出您的期望是什么,而示例输入和输出将很容易理解。祝你好运。

标签: bash scope pass-by-reference ksh


【解决方案1】:

我找到了解决方案,这家伙做到了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 开发人员所在的线程的链接 表示这是 unset 的预期行为方式,它将保持这种方式。

【讨论】:

    【解决方案2】:

    我发现用语法声明函数:

    function func_a
    

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

    皮特

    【讨论】:

      猜你喜欢
      • 2013-01-19
      • 2014-06-26
      • 1970-01-01
      • 2011-02-15
      • 1970-01-01
      • 2017-01-09
      • 2011-10-28
      • 1970-01-01
      • 2020-09-10
      相关资源
      最近更新 更多