如何避免源脚本中的命名空间冲突/污染?

如何避免源脚本中的命名空间冲突/污染?

我想实现一个foo.sh最终执行命令bar(带有一些参数)的脚本。该命令bar修改当前 shell 环境,这意味着foo.sh必须源自1。 (顺便说一句,实施bar完全超出了我的控制范围。)

中大部分代码的目的foo.sh是计算将传递给 的参数bar

为了保持foo.sh合理的可读性/可维护性,我发现我必须定义许多辅助变量。不幸的是,这为

  1. 命名空间冲突(即破坏现有参数)
  2. 命名空间污染(即用多余的参数扰乱环境)

避免或至少减轻这些问题的一种可能方法是将大部分foo.sh代码放入一个函数中(其所有变量都声明为),该函数回显要在调用范围内local进行 'ed 的合适代码字符串;eval例如

{
  __messy_calculation () {

      local x y z ...
      local bar_arg_1 bar_arg_2 ...
      ...
      echo "bar $bar_arg_1 bar_arg_2 ..."

  }

  eval "$( __messy_calculation )"

} always {

  unfunction __messy_calculation

}

这解决了命名空间污染问题,并将命名空间冲突问题减少到函数名称的问题。 (不过,我不太喜欢使用 eval。)

我认为这种情况很普遍,已经存在解决它的标准方法。如果是这样,请告诉我。


1如果我的推理有缺陷,请让我补充一点,如果我将所有代码(包括对 的调用)bar放入函数中,当我在命令行上执行此函数时,当前环境不受影响,这使得该函数无用。相反,如果我获取执行调用的行bar,则当前环境将按预期进行修改。

答案1

对于变量,可以使用匿名函数(如上面的注释中所述)。这意味着您可以定义任意数量的变量。您想要对前缀为 的调用者隐藏的那些local,您想要与您通常定义的调用者通信的那些:

function {
  local my_var=foo
  your_var=bar
  : ...
}

但对于无法工作的函数,因为它们无法声明local。我有这个问题zshrcunfunction并决定为我的“本地”函数的所有名称添加一个短字符串前缀(就像在 C 中使用命名空间一样)并在末尾添加通配符:

function foo-do-something () {
  : ...
}
function foo-do-some-more-stuff () {
  : ...
}
function foo-main () {
  local my_var=oof
  you_var=rab
  foo-do-something for bar
  foo-do-some-more-stuff with baz
}
foo-main
unfunction -m 'foo-*'

在我看来,这不是最佳解决方案(我更喜欢本地函数),但它对我有用。

答案2

解决方案是使用子 shell、嵌套函数和unsetmain func:

my_app_main()
(
  unset -f my_app_main

  a()
  (
    x=1
    echo "a.x is $x"
  )

  b()
  (
    x=2
    echo "b.x is $x"
  )

  c()
  (
    echo "c.x is $x (empty)"
  )

  a
  b
  c
)

my_app_main "$@"

echo "$x (empty - x is gone)"

# all gone
type my_app_main a b c

相关内容