避免在bash中使用namerefs的意外行为

时间:2019-04-08 00:00:00

标签: bash

为什么这没有给出任何输出(除了换行符)而不是“ foo”?该代码使用在bash 4.3中引入的 nameref ,并且是“对另一个变量的引用”,它“允许间接操作变量”。

如果为库编写代码,应该采取什么措施来防止这种情况发生?

#!/usr/bin/bash

setret() {
   local -n ret_ref=$1
   local ret="foo"
   ret_ref=$ret
}

setret ret
echo $ret

通过bash -x运行它使我旋转,因为看起来它应该输出我期望的foo

+ setret ret
+ local -n ret_ref=ret
+ local ret=foo
+ ret_ref=foo
+ echo


有趣的是,它打印的是bar,而不是foo

#!/usr/bin/bash

setret() {
   local -n ret_ref=$1
   ret_ref="bar"
   local ret="foo"
   ret_ref=$ret
}

setret ret
echo $ret

同样令人困惑的bash -x输出:

+ setret ret
+ local -n ret_ref=ret
+ ret_ref=bar
+ local ret=foo
+ ret_ref=foo
+ echo bar
bar

1 个答案:

答案 0 :(得分:1)

我希望这对其他人很有价值,因为在#bash IRC频道中询问期望的输出得到了它的常规foo之一的响应,这就是我的期望。 / p>

然后,他们让我挺直。 namerefs 不能像我想的那样工作。 local -n未将ret_ref设置为引用$1。而是基本上将字符串ret存储在ret_ref中,标记为在使用时用作参考。

因此,尽管在我看来ret_ref会引用调用者的ret变量,但它只会这样做,直到函数定义了自己的本地ret变量,然后它将引用代替那个。

如果为库编写代码,防止这种情况的唯一有保证的方法是在使用 namerefs 的任何函数中,使用以下所有函数名称为所有非nameref变量添加前缀:

#!/usr/bin/bash

setret() {
   local -n ___setret_ret_ref=$1
   local ___setret_ret="foo"
   ___setret_ret_ref=$___setret_ret
}

setret ret
echo $ret

非常丑陋,但必须避免碰撞。 (当然,可能有一些可行的方法,但是不太确定)。