POSIX-Compliant Way to Scope Variables to a Function in a Shell Script -
is there posix compliant way limit scope of variable function declared in? i.e.:
testing() { test="testing" } testing echo "test is: $test"
should print "test is:". i've read declare, local, , typeset keywords, doesn't required posix built-ins.
it done local
keyword, is, seem know, not defined posix. here informative discussion adding 'local' posix.
however, primitive posix-compliant shell know of used gnu/linux distributions /bin/sh
default, dash
(debian almquist shell), supports it. freebsd , netbsd use ash
, original almquist shell, supports it. openbsd uses ksh
implementation /bin/sh
supports it. unless you're aiming support non-gnu non-bsd systems solaris, or using standard ksh, etc., away using local
. (might want put comment right @ start of script, below shebang line, noting not strictly posix sh script. not evil.) having said that, might want check respective man-pages of these sh
implementations support local
, since might have subtle differences in how work. or don't use local
:
if want conform posix, or don't want mess possible issues, , not use local
, have couple options. answer given lars brinkhoff sound, can wrap function in sub-shell. might have other undesired effects though. way shell grammar (per posix) allows following:
my_function() ( # in sub-shell here, # i'm using ( , ) function's body , not { , }. )
although maybe avoid super-portable, old bourne shells can non-posix-compliant. wanted mention posix allows it.
another option unset
variables @ end of function bodies, that's not going restore old value of course isn't want guess, merely prevent variable's in-function value leak outside. not useful guess.
one last, , crazy, idea can think of implement local
yourself. shell has eval
, which, evil, yields way insane possibilities. following implements dynamic scoping la old lisps, i'll use keyword let
instead of local
further cool-points, although have use so-called unlet
@ end:
# if want can add error-checking , what-not this. @ present, # wrong usage (e.g. passing string whitespace in `let', not # balancing `let' , `unlet' calls variable, etc.) yield # very confusing error messages or breakage. it's dirty code, # wrote down pretty @ 1 go. clean up. let() { dynvar_name=$1; dynvar_value=$2; dynvar_count_var=${dynvar_name}_dynvar_count if [ "$(eval echo $dynvar_count_var)" ] 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() dynvar_name 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
now can:
$ 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
(by way unlet
can given number of variables @ once (as different arguments), convenience, not showcased above.)
don't try @ home, don't show children, don't show co-workers, don't show #bash
@ freenode, don't show members of posix committee, don't show mr. bourne, maybe show father mccarthy's ghost give him laugh. have been warned, , didn't learn me.
edit:
apparently i've been beaten, sending irc bot greybot
on freenode (belongs #bash
) command "posixlocal" make give 1 obscure code demonstrates way achieve local variables in posix sh. here cleaned version, because original difficult decipher:
f() { if [ "$_called_f" ] x=test1 y=test2 echo $x $y else _called_f=x x= y= command eval '{ typeset +x x y; } 2>/dev/null; f "$@"' fi }
this transcript demonstrates usage:
$ x=a $ y=b $ f test1 test2 $ echo $x $y b
so lets 1 use variables x
, y
locals in then
branch of if form. more variables can added @ else
branch; note 1 must add them twice, once variable=
in initial list, , once passed argument typeset
. note no unlet
or needed (it's "transparent" implementation), , no name-mangling , excessive eval
done. seems cleaner implementation overall.
edit 2:
comes out typeset
not defined posix, , implementations of almquist shell (freebsd, netbsd, debian) don't support it. above hack not work on platforms.
Comments
Post a Comment