myFunc(){
parse "$1" && #parse() is a test
eval " shift #$1 is a valid, eval-safe name
local name$1 ${1#=}="'("$@")' #$1 is expanded before shift
}
parse()
case ${1#=} in
("$1"|""|[0-9]*|*[!_[:alnum:]]*) ! : #return false for all invalid names
esac
It does also work without eval
given another execution step or two:
myFunc(){
local -a "name$1[@]" "${1#=}"='("${@:2}")' &&
[ -z "${1%=*}" ] && printf %s\\n "${!name}"
}
In that case I just allow the local
builtin to do all of the validation and assignment at once. Basically, if the local
command can assign "${1#=}"=("${@#"$1"}")
successfully and "${1%=*}"
is null then you know the assignment has taken place successfully. Any syntax error - such as bad shell names - will automatically fail and return
with error during the local
assignment, and the simple validation [
test ]
which follows is all that is necessary to ensure that you don't accidentally do local name=morename=("${@#"$1"}")
.
The natural upshot to this is that when a bad name is passed in as =$1
the shell will automatically print out a meaningful error message to stderr for you and do all of the error handling automatically with no fuss.
Like this:
myFunc =goodname 1 2 3 'and some ;more' &&
myFunc =bad-name 1 2 3 'and some ;more'
1
2
3
and some ;more
bash: local: `bad-name=("${@:2}")': not a valid identifier
Note that doing function
name
(){
list
;}
is almost definitely not what you mean to do.
If you intend to localize the function's traps and similar you need function
name
{
list
;}
.
If you intend to share all state but your local
ly defined variables with the current shell then function
name
(){
list
;}
or name
()
list
are equivalent because the function
keyword is ignored by the shell (except that some shells which implement it tend to parse the following list
incorrectly if it is not contained in curly braces) when name
is followed by ()
.
"$@"
instead of plain$@
. Also, you don't need to quote'bar'
and'baz'
, but, as long as you are doing so, you should probably quote=RESULT_PREF
, too, to make it clear that you're treating it as just a string parameter.