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 ()
.