我想实现一个foo.sh
最终执行命令bar
(带有一些参数)的脚本。该命令bar
修改当前 shell 环境,这意味着foo.sh
必须源自1。 (顺便说一句,实施bar
完全超出了我的控制范围。)
中大部分代码的目的foo.sh
是计算将传递给 的参数bar
。
为了保持foo.sh
合理的可读性/可维护性,我发现我必须定义许多辅助变量。不幸的是,这为
- 命名空间冲突(即破坏现有参数)
- 命名空间污染(即用多余的参数扰乱环境)
避免或至少减轻这些问题的一种可能方法是将大部分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、嵌套函数和unset
main 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