Here's another revised version. It seems like a lot of bookkeeping (I wish we could transfer to bash?), but I don't see another way if you want to pass "variables by reference" in a bash library and prevent both yourself and public users from being bitten by a conflict with a local variable - other than obfuscating your library local variables.
I hope we can get it right, so it can be used with a revised version of the `_get_cword' function of the bash-completion package (= blackbox). There are still some questions: I have to give local variables a value (append an equal sign) in order to get them listed with 'local' in "blackbox()". Is there a bash builtin which lists all defined local variable names, even those not having a value yet? I also want to let 'blackbox' return array variables, which doesn't seem to be possible with the 'printf/read' workarounds, so I have to use 'eval' and still need to sanitize the array variable names. What's considered good sanitizing: I'm now checkin for $' \n\t;:$' in "_blackbox_var_sane()"? Other changes are: Called private function _after_ collission test. Output error messages to stderr and return non-zero value. Added check to enforce private function "_blackbox()" is ALWAYS called via public "blackbox()". I thought about whether private function "_blackbox()" should also have a check for having local conflicts, but I figured this should be covered by blackbox unit tests :-) Added an input parameter and return value for the sake of completeness. Here's the code: # Output error of variable by reference conflicting with local # Params: $1 Variable name causing conflict # $2 Function in which conflict occurs _blackbox_var_conflict() { echo "ERROR: variable name conflicts with local variable:"\ "'$1', in function: $2()" 1>&2 } # Check whether private function is being called by public interface # Params: $1 Function name of public interface # Return: False (1) if error _blackbox_called_by() { if [[ ${FUNCNAME[2]} != $1 ]]; then echo "ERROR: ${FUNCNAME[1]}() MUST be called by $1()" 1>&2 return 1 fi } # Check whether variable is sane to be used as eval assignment # Param: $1 Variable name # Return: False (1) if not sane _blackbox_var_sane() { if [[ ! $1 || ${1//[$' \n\t;:$']} != $1 ]]; then echo "ERROR: invalid identifier: '$1'"\ "passed to function: ${FUNCNAME[1]}()" 1>&2 return 1 fi } # Private library function. Do not call directly. See blackbox() _blackbox() { _blackbox_called_by blackbox || return 1 local a b c d e f g h i j arr=( foo "bar cee" ) # ... # Lots of complicated library code here # ... [[ $2 ]] && printf -v $2 %s b # Return value _blackbox_var_sane "$3" && # Return array value eval $3=\( \"\${a...@]}\" \) || return 1 return 0 # Return exit status } # Param: $1 input argument # Param: $2 variable name to return value to # Param: $3 variable name to return array value to # Public library function blackbox() { # NOTE: Give all locals a value so they're listed with 'local' local __2= __3= __x= __v= IFS=$'\n' # Check arguments conflicting with locals for __v in $(local); do case ${__v%=*} in $2|$3) _blackbox_var_conflict ${__v%=*} $FUNCNAME; return 1;; esac done _blackbox "$1" __2 __3 # Call private function __x=$? # Catch exit status [[ $2 ]] && printf -v $2 %s "$__2" # Return value _blackbox_var_sane "$3" && # Return array value eval $3=\( \"\${_...@]}\" \) || return 1 return $__x # Return exit status } blackbox i a b; printf $'%s\n' $a "$...@]}" # Outputs vars all right blackbox i __2 __3 # Outputs error d='ls /;true'; blackbox i "$d" "$d" # No oops _blackbox a # Force public access Freddy Vulto http://fvue.nl/wiki/Bash:_passing_variables_by_reference