Testing() { TEST="testing" } Testing echo "Test is: $TEST"
应该打印“测试是:”。我已经阅读了关于声明,本地和排版的关键字,但它看起来不像POSIX内置的。
然而,即使是最原始的符合POSIX的shell,我知道一些GNU / Linux发行版使用哪个作为/ bin / sh默认,dash(Debian Almquist Shell)支持它。 FreeBSD和NetBSD使用ash,原来的Almquist Shell也支持它。 OpenBSD使用/ bin / sh的ksh实现也支持它。所以除非你的目标是支持像Solaris这样的非GNU非BSD系统,还有那些使用标准的ksh等,那么你可以使用本地的方法来避免。 (可能想在脚本开始时放下一些评论,在shebang行之下,注意到它不是一个严格的POSIX sh脚本,只是不是邪恶的)所有这一切,你可能想检查相应的所有这些支持本地的sh实现的手册页,因为它们的工作方式可能有微妙的差异。或者不要使用本地:
如果你真的想要完全符合POSIX,或者不想混淆可能的问题,因此不使用本地,那么你有几个选项。 Lars Brinkhoff给出的答案是声音,你可以把这个功能包装在一个子shell中。这可能会有其他不良影响。通过shell语法(每个POSIX)允许以下内容:
my_function() ( # Already in a sub-shell here,# I'm using ( and ) for the function's body and not { and }. )
虽然可能避免超级便携式,但一些旧的Bourne外壳甚至可以与POSIX兼容。只是想提到POSIX允许它。
另一个选择是在函数体的末尾取消设置变量,但是当然不会恢复旧值,所以不是真的想要的,我猜这只会阻止变量的函数内值泄漏。不是很有用我猜
我可以想到的最后一个,疯狂的想法是实现本地自己。 shell具有eval,但是它是邪恶的,可以产生一些疯狂的可能性。以下基本上实现了一个旧的Lisps的动态范围,我将使用关键字let而不是本地进一步的酷点,尽管你必须使用所谓的unlet结尾:
# If you want you can add some error-checking and what-not to this. At present,# wrong usage (e.g. passing a string with whitespace in it to `let',not # balancing `let' and `unlet' calls for a variable,etc.) will probably yield # very very confusing error messages or breakage. It's also very dirty code,I # just wrote it down pretty much at one go. Could clean up. let() { dynvar_name=$1; dynvar_value=$2; dynvar_count_var=${dynvar_name}_dynvar_count if [ "$(eval echo $dynvar_count_var)" ] then eval $dynvar_count_var='$(( $'$dynvar_count_var' + 1 ))' else eval $dynvar_count_var=0 fi eval dynvar_oldval_var=${dynvar_name}_oldval_'$'$dynvar_count_var eval $dynvar_oldval_var='$'$dynvar_name eval $dynvar_name='$'dynvar_value } unlet() for dynvar_name do dynvar_count_var=${dynvar_name}_dynvar_count eval dynvar_oldval_var=${dynvar_name}_oldval_'$'$dynvar_count_var eval $dynvar_name='$'$dynvar_oldval_var eval unset $dynvar_oldval_var eval $dynvar_count_var='$(( $'$dynvar_count_var' - 1 ))' done
现在你可以:
$ let foobar test_value_1 $ echo $foobar test_value_1 $ let foobar test_value_2 $ echo $foobar test_value_2 $ let foobar test_value_3 $ echo $foobar test_value_3 $ unlet foobar $ echo $foobar test_value_2 $ unlet foobar $ echo $foobar test_value_1
(通过unlet可以一次给出任何数量的变量(作为不同的参数),为方便起见,不在上面显示。)
不要在家里试试,不要把它显示给孩子,不要显示你的同事,不要在Freenode显示#bash,不要显示给POSIX委员会的成员,不应该告诉Bourne先生,也许把它展示给麦卡锡的父亲给他一个笑。你被警告过,你没有从我那里学习。
编辑:
显然我被殴打,在Freenode(属于#bash)上发送IRC bot greybot命令“posixlocal”将使它给出一些模糊的代码,演示了一种在POSIX sh中实现局部变量的方法。这是一个有点清理的版本,因为原来很难解读:
f() { if [ "$_called_f" ] then x=test1 y=test2 echo $x $y else _called_f=X x= y= command eval '{ typeset +x x y; } 2>/dev/null; f "$@"' fi }
本记录表明用法:
$ x=a $ y=b $ f test1 test2 $ echo $x $y a b
所以它可以使用变量x和y作为if表单的then分支中的本地化。更多变量可以添加到else分支;请注意,必须将它们两次添加,一次与初始列表中的variable =一样,并作为参数传递给排版。请注意,不需要等等(这是一个“透明”的实现),并且没有名称变化和过多的eval完成。因此,整体来说,这似乎是一个更清洁的实现。
编辑2:
出版排版不是由POSIX定义的,Almquist Shell(FreeBSD,NetBSD,Debian)的实现不支持它。所以上述黑客在这些平台上不行。