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
Ele também funciona sem eval dado outra etapa de execução ou duas:
myFunc(){
local -a "name$1[@]" "${1#=}"='("${@:2}")' &&
[ -z "${1%=*}" ] && printf %s\n "${!name}"
}
Nesse caso, apenas permito que o local builtin faça toda a validação e atribuição de uma só vez. Basicamente, se o comando local puder atribuir "${1#=}"=("${@#"$1"}") com sucesso e "${1%=*}" for nulo, você saberá que a atribuição ocorreu com sucesso. Qualquer erro de sintaxe - como nomes de shell inválidos - falhará automaticamente e return com erro durante a atribuição local , e a validação simples [ test ] que segue é tudo o que é necessário para garantir que você não usa t acidentalmente local name=morename=("${@#"$1"}") .
O resultado natural disso é que quando um nome ruim é passado como =$1 , o shell automaticamente imprimirá uma mensagem de erro significativa para stderr e fará todo o tratamento de erros automaticamente sem confusão.
Assim:
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
Observe que fazer function name (){ list ;} definitivamente não é o que você pretende fazer.
Se você pretende localizar as armadilhas da função e semelhantes, precisará de function name { list ;} .
Se você pretende compartilhar todos os estados, mas suas local ly variáveis definidas com o shell atual, então function name (){ list ;} ou name () list são equivalentes porque a palavra-chave function é ignorada pelo shell (exceto que alguns shells que o implementam tendem a analisar incorretamente o seguinte list incorretamente se ele não estiver contido nas chaves quando name é seguido por () .