我想实现一个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
}
Run Code Online (Sandbox Code Playgroud)
这解决了命名空间污染问题,并将命名空间冲突问题减少到函数名称的问题。(不过,我不太喜欢使用 eval。)
我认为这种情况很普遍,已经存在解决它的标准方法。如果是这样,请告诉我。
1如果我的推理有缺陷,请让我补充一点,如果我将所有代码(包括对 的调用)放入bar函数中,当我在命令行上执行此函数时,当前环境不受影响,这使得该函数无用。相反,如果我获取执行调用的行bar,则当前环境将按预期进行修改。
对于变量,可以使用匿名函数(如上面的注释中所述)。这意味着您可以定义任意数量的变量。您想要对前缀为 的调用者隐藏的那些local,您想要与您通常定义的调用者通信的那些:
function {
local my_var=foo
your_var=bar
: ...
}
Run Code Online (Sandbox Code Playgroud)
但对于无法工作的函数,因为它们无法声明local。我在zshrc中遇到了这个问题,并决定为“本地”函数的所有名称添加一个短字符串前缀(就像在 C 中使用命名空间一样),并unfunction在末尾添加通配符:
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-*'
Run Code Online (Sandbox Code Playgroud)
在我看来,这不是最佳解决方案(我更喜欢本地函数),但它对我有用。